Skip to content

Tuning

Most workloads run well on defaults. Reach for these knobs when you’ve measured a specific bottleneck.

When latency is the problem

  1. Profile per-stage:

    Terminal window
    export NAMIDB_PROFILE_DUMP=1

    This pinpoints whether time is in parse, lower, optimise, or execute.

  2. EXPLAIN VERBOSE to see the plan and selectivity estimates.

  3. If execute dominates and the plan looks reasonable, try factorization:

    Terminal window
    export NAMIDB_FACTORIZE=1

    Big win on path-heavy queries (IC09, IC11) where intermediate results explode under non-factorized evaluation.

When memory is the problem

Cap the caches:

Terminal window
export NAMIDB_ADJACENCY_BUDGET_MB=256
export NAMIDB_NODE_CACHE_BUDGET_MB=256
export NAMIDB_SST_CACHE_BUDGET_MB=512

All three are eviction-bounded — never exceed the budget.

Or disable one entirely:

Terminal window
export NAMIDB_ADJACENCY=off
export NAMIDB_NODE_CACHE=off

For the embedded use case inside small containers / Lambdas, a common profile is “small NodeCache, no SstCache, full AdjacencyCache”.

When write throughput is the problem

  • Bulk-stage instead of per-row CREATE — use merge_nodes / merge_edges from Python, or upsert_node / upsert_edge from Rust. These amortise a single commit_batch() over thousands of rows.

  • Increase flush interval on namidb-server if you’re doing burst-write workloads:

    Terminal window
    --flush-interval 5m

    Larger memtables → fewer L0 SSTs → less compaction work.

  • Shard by namespace. Each namespace has one writer. Two unrelated workloads on two namespaces double your write throughput.

When cold-read latency is the problem

This is dominated by SST fetch from the bucket. Options:

  • Move the daemon closer to the bucket. Same region, same VPC.
  • Pre-warm with a one-time query that touches the working set — subsequent queries hit the SST cache.
  • Bump NAMIDB_SST_CACHE_BUDGET_MB so the working set fits.

See also