- Will my rule use WCOJ? (which shapes and key types qualify)
- Why did an eligible rule still fall back to the ordinary join?
- Which settings move the decision, and how do I confirm the change?
When to use this
Reach for this page when you have a triangle, 4-cycle, or clique query over a large, skewed graph and you want to confirm — or force — that XLOG runs it with WCOJ. It is also the page to open when a rule you expected to speed up did not, and you need to find out why.How you confirm it worked
Two signals, together, tell you a tuning change did what you wanted:- Dispatch counters report whether the WCOJ route actually fired for your rule, or whether XLOG quietly ran the ordinary binary join instead.
- Row-set equality confirms correctness: the WCOJ route and the ordinary join must return the identical set of rows.
--wcoj --stats:
triangle count means your triangle rule dispatched to WCOJ. If instead
you see
When WCOJ dispatches
The promoter recognizes eligible join shapes; a runtime cost gate then chooses the worst-case-optimal multiway join or the binary-join fallback — and the two return the identical row set.
1
The body is positive relational Datalog
Every body atom is a relation scan. Negation, aggregation,
is expressions, ground
facts, and too-few positive atoms all disqualify the rule.2
The body matches a certified shape
XLOG certifies a fixed set of join geometries — a triangle
e(X,Y), e(Y,Z), e(X,Z),
a 4-cycle e(W,X), e(X,Y), e(Y,Z), e(Z,W), and K5 / K6 cliques (a clique on
K nodes, where every one of the C(K,2) possible edges is present). Shapes
outside this set are not automatically routed through WCOJ.3
The join keys are a supported type
WCOJ join keys must be
u32, u64, or Symbol, and a single dispatch cannot mix
width classes — that is, it cannot mix 32-bit and 64-bit keys. (Symbol shares
u32’s physical layout.)Eligible is not the same as dispatched
This is the point most people miss. A rule can clear every check above and still run on ordinary binary joins. There are two decisions, not one. First the rule is promoted into aMultiWayJoin plan node — the plan step that represents the whole multiway
pattern. Promotion makes the rule eligible. Then, at runtime, a second
decision — based on cost estimates and table statistics — decides whether the
rule is actually dispatched to WCOJ.
Every promoted MultiWayJoin carries an embedded fallback: the post-optimizer binary
plan that would have run without promotion. When the dispatcher declines WCOJ,
the executor runs that embedded fallback instead.
Common reasons the dispatcher declines an eligible rule:
- The cost model, given the available statistics, predicts the binary plan wins.
- Statistics are missing or too thin for the cost model to justify WCOJ.
- The best available join order would have to start from a bad prefix — one that materializes a larger intermediate than the binary plan — so the planner declines rather than dispatch the loss.
- A kill switch (a hard off switch) or a force-off setting is active (see below).
- Runtime validation fails — missing relation buffers, mixed width classes, or a projection that does not match the certified shape.
- For a
K-clique, the statistics are incomplete or a hash-join route is predicted to win. This is a planned hash route, not a missed recognition.
Environment-variable controls
Environment variables are process-global: set them once at process startup. In tests, prefer the per-runtime builders below so one test’s setting does not bleed into another. Unset, empty,0, and false never force a route on.
Two triangle controls are exposed as runtime-config builders instead of environment
variables: triangle adaptive dispatch (which is on by default) and triangle
hard-disable. Use
with_wcoj_triangle_dispatch_adaptive(...) and
with_wcoj_triangle_dispatch_disabled(...) for those two.Factorized execution controls
The three variables below govern factorized execution — an extension that computes
larger join and aggregate patterns without expanding them into full intermediate tables.
It covers three features: GPU Free Join (a WCOJ-style engine for general multiway
bodies), factorized recursive deltas (compact incremental updates during recursion),
and aggregate-fused WCOJ (combining a count/sum/min/max with the join in one pass).These features and controls have been available since 0.10.0. See the
factorized execution guide for details.
Per-runtime and compile-time builders
When one process needs different WCOJ behavior for different executors — or you want to avoid process-global environment variables in tests — configureRuntimeConfig and
attach it to the executor. Forcing triangle WCOJ, as below, is the usual first step in
an A/B row-set comparison:
RuntimeConfig decides whether a recognized shape dispatches at runtime.
CompilerConfig is a separate setting: it decides whether the compiler emits a
non-default variable ordering for triangle and 4-cycle plans — the order in which
the join binds its variables, which fixes the “leader” relation the join starts from.
The default preserves the baseline leader order. Enable a heat-aware ordering (one that
prefers relations the workload touches most) only when statistics are meaningful:
wcoj_var_ordering_threshold is a ratio gate. The model rotates the leader only when
candidate_score / default_leader_score is at or below the threshold. The default is
0.5; smaller values demand a clearer win before rotating. Values outside the interval
(0.0, 1.0], plus NaN and infinity, clamp back to the default.
Choosing a cost model
There are two independent cost-model layers. One picks whether to use WCOJ at all; the other picks the join order once you do. Runtime dispatch picks whether an eligible shape dispatches:CostModelKind::Cardinalityis the default. Use it when relation cardinalities and observed selectivity are populated, or when you just want the production route.CostModelKind::SkewClassifieris the conservative opt-out. Use it to prove fallback behavior or to bisect a suspected dispatch regression.
WcojVarOrderingKind::Disabled(default) keeps bit-identical leader order to the original slices.LeaderCardinalitypicks the smallest relation as leader when the threshold gate shows a clear win — the simplest useful model.HeatAwarecombines cardinality, relation heat (how often a relation is touched), and observed selectivity. Use it for skewed graphs or repeated workloads where theStatsManager(XLOG’s runtime statistics tracker) has enough evidence to identify hot relations.
Tuning workflow
Tune one knob at a time, and for each change record both the dispatch counters and row-set equality. Never trust a speedup you have not proven row-equivalent.wcoj_var_ordering_threshold— lower it (for example0.25) when leader rotation is too eager and layout overhead dominates; raise it toward0.75only after row parity is stable and profiling shows the default leader is repeatedly expensive.XLOG_WCOJ_BLOCK_WORK_UNIT— lower it for severe leader-key skew where a few keys dominate work; raise it for uniform inputs where launch overhead dominates. Stay within1..8192. This knob must not change row sets.- Force gates — use them to prove the WCOJ route produces the same rows, not as a permanent substitute for a cost model. Leave them on only for a fixed, benchmarked workload.
Debug checklist
When WCOJ did not run:- Check the shape — is it a triangle, 4-cycle, or
K5/K6clique? - Check the key types — are they
u32,u64, orSymbol? - Check env and config — did you force off or disable the route?
- Check statistics — does the cost model have enough cardinality and selectivity?
- Check counters — did the route fire but emit zero rows?
- Check fallback parity — does forced-off output match the expected rows?
- Confirm the input is large enough to amortize layout and launch overhead.
- Try
LeaderCardinalityorHeatAware, but only with meaningful statistics. - Tune
XLOG_WCOJ_BLOCK_WORK_UNITin one direction at a time. - For 4-cycle, verify adaptive mode was intentionally enabled.
- For
K-clique, check whether the planner predicted hash but force was used anyway.
Factorized execution
GPU Free Join, factorized recursive deltas, and aggregate-fused WCOJ — the
routes available since 0.10.0 that extend WCOJ beyond the certified shapes.