You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
like and in applied to a vector never dispatch to the worker pool. The same
predicates inside a select do. On a 16-thread host that is a 4-6x gap for like, and it also inflates the in gap reported in #593.
Comparison primitives are not affected — == over the same column scales.
Measurement
like over a 10M-element SYM column (2.62M distinct, ~303 MB symbol heap),
median of 5, same data in all three rows:
-c 1
-c 2
-c 4
-c 8
-c 16
scaling
(sum (like url "*google*"))
238.8
231.2
229.0
224.4
226.2 ms
1.06x
select where: (in-memory)
159.4
80.2
52.0
45.0
39.8 ms
4.0x
select where: (parted)
76.0
44.4
26.6
22.0
20.6 ms
3.7x
The bare form is flat across the whole range — it is serial. Note it is also
1.5x slower than the fused form at -c 1, so parallel dispatch is the larger
part of the gap but not all of it.
in behaves the same way, and == does not. 351,393-element SYM column:
-c 1
-c 4
-c 16
scaling
(sum (== col s))
100
20
20 us
5.0x
(sum (in col one))
2660
1920
1900 us
1.4x
(sum (in col many))
4180
3660
3660 us
1.14x
select where: (== c s)
140
60
80 us
2.3x
Reproducer
(set NL 351393)
(set insts (as 'SYM (map (fn [i] (format"INST%" i)) (til 766))))
(set col (take insts NL))
(set one (take insts 1))
(sett (table [c] (list col)))
(set s (first insts))
(set bench
(fn [name n f]
(do (f) (let t0 (.time.now)) (let i 0)
(while (< i n) (f) (let i (+ i 1)))
(println name "" (/ (*1000.0 (- (.time.now) t0)) n) " us"))))
(bench "BARE (== col s) "50 (fn [] (sum (== col s))))
(bench "BARE (in col one) "50 (fn [] (sum (in col one))))
(bench "FUSED select == s "50 (fn [] (count (select {from: twhere: (== c s)}))))
Run at -c 1 and -c 16 and compare. == scales, in does not.
Why it matters
It is invisible. Both forms are correct and idiomatic, and nothing
indicates that one is single-threaded. Lifting a predicate out of a select
into a variable — a refactor that looks free — silently costs the pool.
Dispatch vector like and in the way == is already dispatched, or document
that these primitives are serial outside a query so the fused form can be
chosen deliberately.
We are not blocked: our own hot paths use the fused form. This was found while
measuring #606 and looks like a straightforward gap rather than a design choice.
Measured on rayforce 2.6.2.r237.gc5556113, 8 physical / 16 logical
(Ryzen AI 7 350).
Summary
likeandinapplied to a vector never dispatch to the worker pool. The samepredicates inside a
selectdo. On a 16-thread host that is a 4-6x gap forlike, and it also inflates theingap reported in #593.Comparison primitives are not affected —
==over the same column scales.Measurement
likeover a 10M-element SYM column (2.62M distinct, ~303 MB symbol heap),median of 5, same data in all three rows:
-c 1-c 2-c 4-c 8-c 16(sum (like url "*google*"))select where:(in-memory)select where:(parted)The bare form is flat across the whole range — it is serial. Note it is also
1.5x slower than the fused form at
-c 1, so parallel dispatch is the largerpart of the gap but not all of it.
inbehaves the same way, and==does not. 351,393-element SYM column:-c 1-c 4-c 16(sum (== col s))(sum (in col one))(sum (in col many))select where: (== c s)Reproducer
Run at
-c 1and-c 16and compare.==scales,indoes not.Why it matters
It is invisible. Both forms are correct and idiomatic, and nothing
indicates that one is single-threaded. Lifting a predicate out of a
selectinto a variable — a refactor that looks free — silently costs the pool.
It distorts
inwith a one-element right side builds a hash instead of lowering to an equality scan (~27x) #593. That issue reports(in col one)at 67x(== col x).That ratio is two defects stacked, and they separate cleanly by core count:
So roughly 3.6x of the gap on a 16-thread host is
==scaling whileinstays serial; the remaining ~27x is the hash-vs-scan issue
inwith a one-element right side builds a hash instead of lowering to an equality scan (~27x) #593 is reallyabout. Worth separating there, since fixing one does not fix the other.
It interacts with Execution pool recruits every core regardless of work size: 2.7x the CPU for 1.2x the speed #599/Worker pool defaults to logical CPUs, not physical cores: ~2x the CPU on SMT hosts #606. Discussion there is about the pool recruiting
too many workers; this is a set of primitives that recruit none.
What we would ask for
Dispatch vector
likeandinthe way==is already dispatched, or documentthat these primitives are serial outside a query so the fused form can be
chosen deliberately.
We are not blocked: our own hot paths use the fused form. This was found while
measuring #606 and looks like a straightforward gap rather than a design choice.
Measured on
rayforce2.6.2.r237.gc5556113, 8 physical / 16 logical(Ryzen AI 7 350).