fix(migration): include id in compress_orderby for hypertables#180
fix(migration): include id in compress_orderby for hypertables#180TerrifiedBug merged 1 commit intomainfrom
Conversation
The hypertables migration changed each hypertable's primary key to (id, timestamp). TimescaleDB rejects ALTER TABLE ... SET (compress, ...) unless every column of the hypertable's unique indexes is present in either compress_segmentby or compress_orderby — so the next migration errored with 'column id must be used for segmenting or ordering' on every TimescaleDB-enabled deployment. Adding id to compress_orderby satisfies the constraint without harming compression: id is a high-cardinality cuid, so segmenting by it would produce one segment per row and destroy the ratio.
Greptile SummaryAdds Confidence Score: 5/5Safe to merge — targeted, correct fix with no regressions on plain PostgreSQL. The change is a minimal, well-reasoned fix: No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Migration starts] --> B{timescaledb extension present?}
B -- No --> C[RAISE NOTICE: skipping\nno-op on plain Postgres]
B -- Yes --> D[PipelineMetric\ncompress_segmentby=pipelineId\ncompress_orderby=timestamp DESC, id]
D --> E[add_compression_policy\ncompress_after=24h]
E --> F[NodeMetric\ncompress_segmentby=nodeId\ncompress_orderby=timestamp DESC, id]
F --> G[add_compression_policy\ncompress_after=24h]
G --> H[PipelineLog\ncompress_segmentby=pipelineId\ncompress_orderby=timestamp DESC, id]
H --> I[add_compression_policy\ncompress_after=24h]
I --> J[NodeStatusEvent\ncompress_segmentby=nodeId\ncompress_orderby=timestamp DESC, id]
J --> K[add_compression_policy\ncompress_after=24h]
K --> L[RAISE NOTICE: compression policies enabled]
Reviews (1): Last reviewed commit: "fix(migration): include id in compress_o..." | Re-trigger Greptile |
#182) Bare SELECT inside a PL/pgSQL DO block is invalid when the result is discarded — Postgres raises 42601 "query has no destination for result data". Switch the four add_compression_policy calls to PERFORM so the migration applies cleanly on TimescaleDB. Follows #179, #180, #181 — same file, same DO block.
Summary
Follow-up to #179. Bringing up the demo on TimescaleDB surfaced two further bugs in
20260329000001_timescaledb_compression. Both are in this PR.Bug 1 —
idmissing from segmentby/orderbyThe previous migration changed each hypertable's primary key to
(id, timestamp). TimescaleDB then refuses to enable compression unless every column of the hypertable's unique indexes appears in eithercompress_segmentbyorcompress_orderby. Theidcolumn was in neither.Fix: add
idas a secondarycompress_orderbycolumn for all four hypertables. Choosing orderby (not segmentby) becauseidis a high-cardinality cuid — segmenting by it would produce one segment per row and destroy the compression ratio.Bug 2 — option-string parser folds identifiers to lowercase
Same case-sensitivity bug class as #179, but on the segmentby/orderby option strings instead of the
regclassargument. Prisma's columns are camelCase (pipelineId,nodeId), and the option-string parser folds unquoted identifiers to lowercase — so'pipelineId'was being looked up aspipelineid.Fix: wrap every column name in double quotes inside the option strings. Same pattern as the table-name fix in #179.
Final state of each ALTER TABLE
…and analogous for
NodeMetric("nodeId"),PipelineLog("pipelineId"),NodeStatusEvent("nodeId").Why this didn't surface earlier
Same as #179: every prior deployment ran on plain Postgres, where the
IF EXISTS (... timescaledb)guard makes this whole migration a no-op. The hosted demo ontimescale/timescaledb:2.16.0-pg16is the first environment in the wild with the extension installed.Recovery instructions
For anyone whose DB is currently in the failed state on this migration:
Option A — wipe and reapply (cleanest if no real data, e.g. demo):
Option B — preserve data:
Drift warning for plain-Postgres users
Same caveat as #179: the migration's checksum changes. On next
prisma migrate deployyou may see a "migration was modified after applied" warning. Resolve with:One-time fix; the no-op behaviour on plain Postgres is unchanged.
Test plan
"id"20260329000000and20260329000001apply cleanlySELECT hypertable_name, attname, segmentby_column_index, orderby_column_index FROM timescaledb_information.compression_settings;— should showpipelineId/nodeIdas a segmentby column andtimestamp+idas orderby columns