mirror of
https://github.com/SigNoz/signoz.git
synced 2026-09-27 05:40:40 +01:00
<!--A few plain bullets saying what changed and why, for a reviewer
skimming it - not a wall of text, not a restatement of the diff, not
generated boilerplate.-->
#### Description
Materialized existence checks now render as an explicit comparison
instead of a bare bool column. Results are unchanged; only skip-index
usage improves.
```sql
-- before
WHERE `attribute_string_gen_ai$$request$$model_exists`
OR `attribute_string_gen_ai$$provider$$name` = 'anthropic'
-- after
WHERE `attribute_string_gen_ai$$request$$model_exists` = true
OR `attribute_string_gen_ai$$provider$$name` = 'anthropic'
```
<details>
<summary>EXPLAIN indexes = 1 (trace-matching phase, 123M
spans)</summary>
Before: bare `col_exists`
```
Name: idx_gen_ai_span_exists
Granules: 15193/15193
Name: <Combined skip indexes>
Granules: 15193/15193
```
After: `col_exists = true`
```
Name: idx_gen_ai_span_exists
Granules: 15193/15193
Name: <Combined skip indexes>
Granules: 488/15193
```
</details>
----
- ClickHouse can use a different skip index for each side of an OR and
union the results, but it can't when one side is a bare bool column.
Comparing with `= true` fixes that.
- This shape comes from the AI explorer trace list with a span filter: a
trace qualifies when it has a gen_ai span *and* a span matching the
filter (possibly different spans), so the WHERE is `(gen_ai gate) OR
<filter>` followed by a HAVING.
- Needs the gen_ai materialized columns and `idx_gen_ai_span_exists`
from SigNoz/signoz-otel-collector#929; without them there's no index to
combine.
<!--Reference issues using `Closes #issue-number` to enable automatic
closure on merge. -->
#### Issues closed by this PR
Part of https://github.com/SigNoz/nerve-pod/issues/282
<!--Anything reviewers should keep in mind while reviewing -->
#### Additional Information
- Benchmarked the AI trace list filtered on `gen_ai.provider.name`
against a 123M-span table (direct I/O, caches off): from ~30M spans in
the window, latency drops 16–17% and CPU 35–38%, with ~25x fewer rows
read (123M spans: 510 → 427 ms, 1.5 → 0.9 sCPU). The saved time and CPU
keep growing with span count, so larger windows save more.
- Single-condition filters (`gen_ai.request.model EXISTS` in dashboard
panels, the AND-ed gate in AI aggregations) already pruned with the bare
form; no change there.