Files
datastore/tests/performance/statistics_simple_if.xml
Manuel acf3a8c63d Add vectorized batch path for the variance family of aggregate functions
Give `AggregateFunctionVarianceSimple` (`varPop`, `varSamp`, `stddevPop`,
`stddevSamp`, `skewPop`, `skewSamp`, `kurtPop`, `kurtSamp`, `covarPop`,
`covarSamp`, `corr`) the same treatment as `groupBitOr`/`groupBitAnd`/
`groupBitXor`: `addBatchSinglePlace`/`addBatchSinglePlaceNotNull` overrides
with vectorized kernels on `VarMoments`/`CovarMoments`/`CorrMoments`.

The `-If`/null flag zeroes the value's bit pattern with an integer mask
(multiplying by the flag would let NaN/Inf in discarded rows poison the
accumulators), and the loops unroll into 16 partial accumulators per moment
- FP addition is not associative, so the compiler cannot do this itself.
This also breaks the sequential FP dependency chain of the per-row path,
so the no-`If` case speeds up as well. `Decimal` inputs keep the generic
per-row path. Dispatch with `MULTITARGET_FUNCTION_X86_V4`, like `sum`.

Measured (50M rows, 1 thread, unpredictable 50% predicate, server-side
query time): `varSampIf`/`stddevSampIf`/`skewSampIf`/`kurtSampIf` -64..-67%,
`covarSampIf`/`corrIf` -59..-62%, `Nullable` -57%, and -35..-68% without
`-If` (`varSamp`/`kurtSamp`/`corr`). Summation order changes, so float
results can differ in the last bits; on integer inputs the moment sums are
exact and results are bit-identical (covered by the test).
2026-07-15 01:05:54 +02:00

27 lines
1.6 KiB
XML

<test>
<query>SELECT varSampIf(number, rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT stddevPopIf(number, rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT skewSampIf(number, rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT kurtSampIf(number, rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT covarSampIf(number, number + 1, rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT corrIf(number, number + 1, rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT varSampIf(toFloat64(number), rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT varSampIf(toFloat32(number), rand32() % 2 = 0) FROM numbers(100000000)</query>
<query>SELECT varSamp(number) FROM numbers(100000000)</query>
<query>SELECT kurtSamp(number) FROM numbers(100000000)</query>
<query>SELECT corr(number, number + 1) FROM numbers(100000000)</query>
<!-- ~20% NULL values, random so the branch predictor doesn't do all the work -->
<create_query>CREATE TABLE nullfloat64_stats (x Nullable(Float64)) ENGINE = Memory</create_query>
<fill_query>INSERT INTO nullfloat64_stats
SELECT IF(rand() % 5 == 0, NULL::Nullable(Float64), toFloat64(cityHash64(number) % 1000000)) AS x
FROM numbers_mt(200000000)
SETTINGS max_threads = 8
</fill_query>
<query>SELECT varSamp(x) FROM nullfloat64_stats</query>
<query>SELECT varSampIf(x, rand32() % 2 = 0) FROM nullfloat64_stats</query>
<drop_query>DROP TABLE IF EXISTS nullfloat64_stats</drop_query>
</test>