Repository navigation
feat: only use pk + block ids to resolve a row - #2320
Conversation
🦋 Changeset detectedLatest commit: d71f347 The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🔵 Tier 2 — Low RiskSmall, isolated change with no API route or data model modifications. Why this tier:
Review process: AI review + quick human skim (target: 5–15 min). Reviewer validates AI assessment and checks for domain-specific concerns. Stats
|
e9e0e51 to
a4f60f3
Compare
E2E Test Results✅ All tests passed • 178 passed • 3 skipped • 1185s
Tests ran across 4 shards in parallel. |
Deep Review🔴 P0/P1 -- must fix
🟡 P2 -- recommended
🔵 P3 nitpicks (10)
Reviewers (10): correctness, testing, maintainability, project-standards, agent-native, learnings-researcher, kieran-typescript, performance, api-contract, adversarial. Testing gaps:
|
…ble persists (#3364) ## Summary Opening log details on large text-log tables is much slower than the search itself (HDX-5696). The side panel already has a fast lookup that filters only on primary key + partition + block columns, but it was gated on the table persisting **both** `_block_number` and `_block_offset`. The affected table only sets `enable_block_offset_column = 1`, so every click fell back to the full-row WHERE, which filters on every selected column (including `Body`) and triggers expensive index loading. This PR relaxes the gate: the fast path is taken when the table persists **either** block column, and the WHERE uses whichever of `_block_number` / `_block_offset` is available. Combined with the primary key, either one is unique enough in practice: two rows would need identical key values (including a nanosecond timestamp) *and* the same insert block or the same offset within their blocks. Tables that persist both columns keep the current behavior; tables with neither still fall back to `__hdx_id` / the full row. Changes: - `getPersistedBlockColumns(engineFull)` in `DBRowTable.tsx` decides which block columns to inject; `useConfigWithAdditionalSelect` uses it for both the extra SELECT keys and `rowKeyColumns`. - Unit tests for the helper and `renderHook` coverage of `useConfigWithAdditionalSelect` (offset only, number only, both, `__hdx_id` fallback, no `sourceId`). - Changeset for `@hyperdx/app`. Known trade-off: rows with identical PK that also share the block number (or the offset) still collide and `LIMIT 1` picks one; the thread on the Linear issue accepted that given nanosecond timestamps. Verified against ClickHouse 26.8 with tables that set only one of the two settings: `engine_full` exposes the setting as matched here, the persisted column survives `OPTIMIZE FINAL` unchanged, and the WHERE shape HyperDX now generates (PK expressions + the block column, no `Body`) returns the clicked row. ### How to test on Vercel preview N/A — the demo tables persist both block columns, so the fast path was already taken there; this change only affects tables that persist one of them. To verify locally, create a table with `SETTINGS enable_block_offset_column = 1` (or `enable_block_number_column = 1`) alone, add it as a log source, click a row and check the side-panel query filters on PK columns + that block column only. ### References - Linear Issue: [HDX-5696](https://linear.app/clickhouse/issue/HDX-5696/speed-up-log-details-lookup-using-primary-key-and-block-offset) - Related PRs: #2071 (introduced block-column detection), #2320 (restricted the row WHERE to PK + block ids) Linear Issue: [HDX-5696](https://linear.app/clickhouse/issue/HDX-5696/speed-up-log-details-lookup-using-primary-key-and-block-offset) <div><a href="https://cursor.com/agents/bc-5fdae508-3c5f-4b0b-a60e-03f5e5eed062?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-5fdae508-3c5f-4b0b-a60e-03f5e5eed062&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> Co-authored-by: Cursor Agent <199161495+cursoragent@users.noreply.github.com>
…kup (#3566) ## Summary Clicking a search result could open the wrong row's details when the table persists only one of `_block_number` / `_block_offset`. - Since #3364 the side panel used a key-only lookup (primary key + partition + whichever block column exists) when at least one block column was persisted. One block column is not unique: `_block_offset` repeats across insert blocks, `_block_number` across the rows of one block, and the primary key often doesn't break the tie (the OTel exporter default keys on the second-precision `TimestampTime`). - Since #3530 the block columns are also detected from server-level `merge_tree_settings`, so on servers that enable only one of them, every table without explicit settings takes this path. - The key-only lookup now requires both block columns. A lone block column is still appended to the full-row lookup as a tiebreaker. - Tables that persist only one block column return to the full-row lookup and lose the #3364 speed-up. A `_part` + `_part_offset` lookup is the follow-up to restore it. ### How to reproduce **Starting point:** `yarn dev`. Set the server default on the dev ClickHouse and restart it: ```sh docker exec <ch-server> sh -c 'echo "<clickhouse><merge_tree><enable_block_offset_column>1</enable_block_offset_column></merge_tree></clickhouse>" > /etc/clickhouse-server/config.d/block_offset.xml' docker restart <ch-server> ``` Create an exporter-shaped table and insert three rows as separate inserts, two in the same second: ```sql CREATE TABLE default.repro_logs ( Timestamp DateTime64(9), TimestampTime DateTime DEFAULT toDateTime(Timestamp), ServiceName LowCardinality(String), SeverityText LowCardinality(String), Body String, LogAttributes Map(LowCardinality(String), String) ) ENGINE = MergeTree PARTITION BY toDate(TimestampTime) PRIMARY KEY (ServiceName, TimestampTime) ORDER BY (ServiceName, TimestampTime, Timestamp); INSERT INTO default.repro_logs (Timestamp, ServiceName, SeverityText, Body) VALUES ('2026-11-05 09:00:39.845', 'saruman', 'INFO', 'Response x_span_id=ESLMARS7L7'); INSERT INTO default.repro_logs (Timestamp, ServiceName, SeverityText, Body) VALUES ('2026-11-05 09:00:39.100', 'saruman', 'INFO', 'Request x_span_id=ESOPOZ7FCV'); INSERT INTO default.repro_logs (Timestamp, ServiceName, SeverityText, Body) VALUES ('2026-11-05 09:00:36.909', 'saruman', 'INFO', 'Request x_span_id=ESLMARS7L7'); ``` Add a log source for `default.repro_logs` (timestamp column `TimestampTime`), then search it for `"ESLMARS7L7"` over a range covering 2026-11-05 09:00 UTC. **On `main`:** 1. Click the `Response x_span_id=ESLMARS7L7` row a few times. 2. The side panel shows `Request x_span_id=ESOPOZ7FCV` about half the time. The query in `system.query_log` is `WHERE ServiceName='saruman' AND TimestampTime=... AND toDate(TimestampTime)=... AND _block_offset='0' LIMIT 1`. **On this branch:** 1. Click the same row. The panel always shows `Response x_span_id=ESLMARS7L7`; the query also filters on `Timestamp`, `SeverityText` and `Body`. ### How to test on Vercel preview N/A — needs a ClickHouse server default; the demo server's user cannot read `system.merge_tree_settings`. ### References - Related PRs: #3530, #3364, #2320, #2071
Summary
Now that we use block numbers and offsets to enforce row uniqueness, we can just use that + a PK to identify a row. There is no need to specify
BodyorSeverityTextand waste i/o and processing time.Testing Locally
Steps:
yarn devenable_block_number_column = 1, enable_block_offset_column = 1WHEREReferences