Skip to content

v3: opclass-path helper functions are LANGUAGE sql — cannot inline, regresses ORE ordered scans 43% vs v2 (validated fix: plpgsql) #353

Description

@coderdan

Problem

eql_v3_internal.jsonb_array_to_bytea_array and eql_v3_internal.jsonb_array_to_ore_block_256 are LANGUAGE sql. In the ore_block_256 btree operator-class call path (index scans, sorts, index builds) SQL functions cannot be inlined, so every invocation pays the per-call SQL-function executor — measured at 3.5× the per-call cost of v2's logic-identical plpgsql equivalents.

This is the root cause of the v2→v3 ORE ordered-scan regression in the release benchmarks (ORE/range_lt_ordered_10: 0.513 → 0.736 ms at 1M, +43%; COMBO/bloom_ore_order_limit: 16.6 → 22.7 ms, +36%). Notably it is NOT the plpgsql comparator — per-query comparator time is identical across v2/v3 (function-level attribution via track_functions), and the v2 vs v3 1M index build times are equal (42 s vs 44 s).

Validated fix

A logic-identical, language-only swap of the two helpers to plpgsql was tested on a live 1M bench database (A→B→A, originals restored):

Scenario (1M) v2 v3 shipped v3 patched
ORE/range_lt_ordered_10 0.513 ms 0.736 ms 0.553 ms
COMBO/bloom_ore_order_limit 16.64 ms 22.70 ms 13.97 ms (16% faster than v2)

Controls without ORE ordering moved ±2.6% (noise). Implementation note: in plpgsql, SELECT <composite> INTO <composite_var> assigns field-wise — return the row constructor directly.

Even better than plpgsql: cache the decoded bytea representation, or do decode+compare in one C pass — per-query attribution splits ~0.19 ms comparator / ~0.26 ms term re-decoding, so a C comparator that still re-parses jsonb per comparison would leave half the cost in place.

Evidence

Full attribution tables and the A→B→A experiment: v3-regressions-report.md on cipherstash/benches#23 (Issue 3 + the COMBO deep-dive). Related: the ORE-vs-OPE gap (0.74 vs 0.12 ms; both ORE versions pay ~0.4–0.5 ms of tracked function time, the fully-inlined OPE path pays zero) — steering ordered workloads to _ord_ope is the structural alternative now that cipherstash-client 0.38.1 emits op.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions