8000 perf: attribute+value patterns scan the whole attribute; AVET index is never read · Issue #518 · project-minigraf/minigraf · GitHub
[go: up one dir, main page]

Skip to content

perf: attribute+value patterns scan the whole attribute; AVET index is never read #518

Closed

Description

@adityamukho

Problem

A pattern with a constant attribute and a constant value, such as [?e :p/name "name-42"], scans every committed fact of the attribute instead of seeking the AVET index. Its cost grows with the attribute's size, not with the answer.

Found by the soak test (#392) on v3 (--profile bench, one matching fact):

Live facts :p/name facts [?e :p/name "name-N"] p50 [:eN ?a ?v] (EAVT) p50
20K (debug) 3.6K 58 ms 0.3 ms
1M 178K 517 ms 0.05 ms
1.35M 240K 761 ms 0.06 ms

Cause

optimizer::select_index picks IndexHint::Avet for this shape, and v8 files keep an AVET tree (meta.avet_root), but CommittedReader has no attribute-and-value lookup. The executor falls back to facts_for_attribute, then filters by value. The AVET tree is written at every checkpoint and checked by verify(), but no query reads it.

Ask

Add an attribute-and-value read to CommittedReader (an AVET prefix scan over a v) and use it for this pattern shape, including refs (IndexHint::Avet for a bound ref value as well). Add a benchmark at 1M facts (#394). Uniqueness lookups ([?e :user/email "…"]) are a common agent-memory and app pattern.

Activity

  1. added this to the v3.0.0 milestone on Oct 10, 2026
  2. adityamukho commented on Oct 10, 2026

    @adityamukho
    CollaboratorAuthor

    Confirmed in code: Matcher::match_pattern_with_hint(&self, pattern, _hint) (src/query/datalog/matcher.rs:305) ignores the hint. The same applies to VAET: a reverse-ref pattern [?e :p/ref #uuid "…"] also scans the attribute. The AVET and VAET trees are written at each checkpoint and walked by verify(), but no query reads them.

  3. adityamukho commented on Oct 10, 2026

    @adityamukho
    CollaboratorAuthor

    At 10M live facts (1.78M :p/name facts, soak test #519, --profile bench): [?e :p/name "name-N"] p50 5.8 s, p99 7.5 s; EAVT point query p50 52 µs.

  4. adityamukho commented on Oct 10, 2026

    @adityamukho
    CollaboratorAuthor

    v2.0.4 behaves the same (soak test on main, #520): [?e :p/name "name-N"] p50 0.9 s at 2M facts. v2.x gets only data-integrity and security fixes, so this is for v3 only.

  5. adityamukho commented on Oct 11, 2026

    @adityamukho
    CollaboratorAuthor

    Parked on branch perf/518-avet-lookup (fe545dc, based on v3 a16f385) until the streaming engine (#473) is done.

    What the branch does (no format change):

    • CommittedReader / Scan gain AttributeValue(attr, &Value) and AttributeKind(attr, ValueKind), read as AVET prefix scans (keys::attribute_value_prefix, attribute_string_prefix, attribute_kind_prefix). Pending facts are filtered within the attribute's AEVT range.
    • selective_fact_fetch maps a constant to the lookups covering every value match_component accepts: a keyword also matches a ref to the entity it names, a UUID also matches keyword values (whole keyword range), a float reads every float of the attribute (epsilon match). An attribute that also appears with a variable value falls back to the whole attribute.
    • Tests: the random-history differential test covers every value type for the new scans; tests/live_reads_test.rs checks the narrow reads against whole-attribute reads (cross-type, :as-of, retractions, reopen).

    Perf envelope at 1M facts (busy machine, to be re-run idle): attribute_value 274 ms → 11 µs p50 (137 → 4 MiB), join_3_scan 1.95 s → 1.53 s, attribute_scan unchanged.

    On revisit: #473's Scan operator should call these reads instead of selective_fact_fetch. Then rebase onto v3, re-run the envelope at 100K/1M/10M on an idle machine, update docs/BENCHMARKS.md (the #518 note and table rows) and CHANGELOG.md, and fix the test count.

  6. adityamukho commented on Oct 14, 2026

    @adityamukho
    CollaboratorAuthor

    Fixed on v3 by PR #588 (#544 PR 1): [?e :a C] reads the AVET range of C in the new streaming engine. 1M facts, #394 envelope: 344 ms → 20 µs p50, 142 → 3 MiB peak RSS.

  7. adityamukho commented on Oct 14, 2026

    @adityamukho
    CollaboratorAuthor

    Closed as covered. What #588 did not finish is tracked here:

    Branch perf/518-avet-lookup stays parked for reference until the streaming engine (#473) is done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    performanceBenchmark performance regressions

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requ 32AA ests

      Issue actions

      0