Artifact Registry ADR 007: carry size in the shadow table's primary key

What

blob_storage_blobs_by_namespace's primary key becomes (namespace_id, sha256) INCLUDE (size), and the document now says which of the table's two indexes serves which read.

Why

!20663 (merged) established that the repository- and artifact-level recomputes resolve each walked digest through the shadow table rather than blob_storage_blobs. It credited that lookup to the covering index on (namespace_id) INCLUDE (size):

the shadow is keyed (namespace_id, sha256) with a covering index on (namespace_id) INCLUDE (size), so the lookup is a single-partition index-only scan

That index cannot serve the lookup. sha256 is neither a key nor an included column in it, so a per-digest lookup goes through the primary key and heap-fetches size for every matched row. The scan is single-partition — namespace_id is a literal — but not index-only.

Adding INCLUDE (size) to the primary key makes the claim true. The cost is size in the primary key's leaf pages, which is the same 8 bytes per row the covering index already carries, on a table whose whole purpose is making these two reads cheap.

Which index serves what, after this

  • Primary key (namespace_id, sha256) INCLUDE (size) — per-digest lookups from repository- and artifact-level reconciliation, index-only.
  • Covering index (namespace_id) INCLUDE (size) — the whole-namespace SUM(size), which has no sha256 to look up and so cannot use the primary key.

The asymmetry runs one way only: the covering index cannot serve the per-digest lookups at all, while the primary key can serve the whole-namespace sum, just over wider entries. Both stay because each is the cheaper scan for one of the two reads.

Downstream

The S22 storage accounting spec in gitlab-org/ops/artifact-registry carries the same correction in !1358, which waits on this one, and the S22 plan (!1296) sizes the shadow's migration against this index set.

Edited by Pawel Rozlach

Merge request reports

Loading
Loading