mirror of
https://github.com/hanzoai/datastore.git
synced 2026-09-26 13:55:07 +00:00
With `max_bytes_ratio_before_external_join` defaulting to `0.5`, the
performance comparison environment (which has memory limits configured)
now wraps hash joins in `SpillingHashJoin`. For perf tests that
specifically benchmark in-memory hash join behavior, this causes the
"new" side to use grace hash join while comparing against an "old"
master that still uses pure hash join, reporting them as regressions.
Set `max_bytes_ratio_before_external_join = 0` in the affected tests to
keep them measuring the same in-memory join code path as before:
* `parallel_hash_join_various.xml` — benchmarks `parallel_hash`.
* `join_convert_to_fixed_hash_table.xml` — benchmarks
`enable_join_fixed_hash_table_conversion` with `hash`/`grace_hash`.
* `join_runtime_filter.xml` — benchmarks runtime filter behavior.
* `join_used_flags.xml` — benchmarks `RIGHT JOIN` used-flag tracking.
* `tpch.xml` — keeps the TPC-H benchmark comparable across runs;
adds an inline `<settings>` block that overrides
`../benchmarks/tpc-h/settings.json`.
CI report: https://s3.amazonaws.com/clickhouse-test-reports/json.html?PR=104285&sha=c0886206419503145375bf5672cbe990b49ae40b&name_0=PR
PR: https://github.com/ClickHouse/ClickHouse/pull/104285
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
123 lines
4.1 KiB
XML
123 lines
4.1 KiB
XML
<test>
|
|
<settings>
|
|
<join_algorithm>parallel_hash</join_algorithm>
|
|
<query_plan_join_swap_table>0</query_plan_join_swap_table>
|
|
<query_plan_convert_outer_join_to_inner_join>0</query_plan_convert_outer_join_to_inner_join>
|
|
<parallel_hash_join_threshold>1</parallel_hash_join_threshold>
|
|
<max_threads>8</max_threads>
|
|
<max_bytes_ratio_before_external_join>0</max_bytes_ratio_before_external_join>
|
|
</settings>
|
|
|
|
<create_query>
|
|
CREATE TABLE IF NOT EXISTS phj_right_nullable (
|
|
key Nullable(UInt64),
|
|
val String
|
|
) ENGINE = Memory
|
|
</create_query>
|
|
|
|
<create_query>
|
|
CREATE TABLE IF NOT EXISTS phj_left (
|
|
key UInt64,
|
|
val String
|
|
) ENGINE = Memory
|
|
</create_query>
|
|
|
|
<create_query>
|
|
CREATE TABLE IF NOT EXISTS phj_asof_left (
|
|
key UInt64,
|
|
ts DateTime,
|
|
val String
|
|
) ENGINE = Memory
|
|
</create_query>
|
|
|
|
<create_query>
|
|
CREATE TABLE IF NOT EXISTS phj_asof_right (
|
|
key UInt64,
|
|
ts Nullable(DateTime),
|
|
val String
|
|
) ENGINE = Memory
|
|
</create_query>
|
|
|
|
<fill_query>
|
|
INSERT INTO phj_left
|
|
SELECT number % 1000, toString(number)
|
|
FROM numbers(5000000)
|
|
</fill_query>
|
|
|
|
<fill_query>
|
|
INSERT INTO phj_right_nullable
|
|
SELECT if(number % 50 = 0, NULL, number % 1000), toString(number)
|
|
FROM numbers(5000000)
|
|
</fill_query>
|
|
|
|
<fill_query>
|
|
INSERT INTO phj_asof_left
|
|
SELECT number % 500, toDateTime('2020-01-01') + number, toString(number)
|
|
FROM numbers(2000000)
|
|
</fill_query>
|
|
|
|
<fill_query>
|
|
INSERT INTO phj_asof_right
|
|
SELECT number % 500, if(number % 30 = 0, NULL, toDateTime('2020-01-01') + number * 2), toString(number)
|
|
FROM numbers(2000000)
|
|
</fill_query>
|
|
|
|
<!-- Parallel hash join with low-cardinality keys: many dispatched blocks will be empty,
|
|
exercising the empty-block skip optimisation in ConcurrentHashJoinResult -->
|
|
<query tag='inner_low_card'>
|
|
SELECT count() FROM
|
|
(SELECT number % 10 AS k FROM numbers_mt(100000)) AS l
|
|
INNER JOIN
|
|
(SELECT number % 10 AS k FROM numbers_mt(100000)) AS r
|
|
USING (k)
|
|
FORMAT Null
|
|
</query>
|
|
|
|
<!-- Parallel hash join contention: many threads competing on few slots -->
|
|
<query tag='inner_contention'>
|
|
SELECT count() FROM
|
|
(SELECT key FROM phj_left LIMIT 1000000) AS l
|
|
INNER JOIN
|
|
(SELECT key FROM phj_left LIMIT 1000000) AS r
|
|
USING (key)
|
|
FORMAT Null
|
|
</query>
|
|
|
|
<!-- RIGHT JOIN with NULLable keys using parallel_hash:
|
|
exercises null_map selector filtering and NotJoinedHash partition iteration -->
|
|
<query tag='right_nullable'>
|
|
SELECT count() FROM phj_left AS l RIGHT JOIN phj_right_nullable AS r ON l.key = r.key
|
|
FORMAT Null
|
|
</query>
|
|
|
|
<!-- FULL JOIN with NULLable keys using parallel_hash -->
|
|
<query tag='full_nullable'>
|
|
SELECT count() FROM phj_left AS l FULL JOIN phj_right_nullable AS r ON l.key = r.key
|
|
FORMAT Null
|
|
</query>
|
|
|
|
<!-- RIGHT JOIN where right side is much larger: stresses not-joined row emission -->
|
|
<query tag='right_asym'>
|
|
SELECT count() FROM
|
|
(SELECT number AS key FROM numbers_mt(100)) AS l
|
|
RIGHT JOIN
|
|
(SELECT number AS key FROM numbers_mt(5000000)) AS r
|
|
USING (key)
|
|
FORMAT Null
|
|
</query>
|
|
|
|
<!-- ASOF JOIN with Nullable timestamps using parallel_hash:
|
|
exercises the selector-aware NULL ASOF key filtering -->
|
|
<query tag='asof_nullable'>
|
|
SELECT count() FROM phj_asof_left AS l
|
|
ASOF LEFT JOIN phj_asof_right AS r
|
|
ON l.key = r.key AND l.ts <= r.ts
|
|
FORMAT Null
|
|
</query>
|
|
|
|
<drop_query>DROP TABLE IF EXISTS phj_right_nullable</drop_query>
|
|
<drop_query>DROP TABLE IF EXISTS phj_left</drop_query>
|
|
<drop_query>DROP TABLE IF EXISTS phj_asof_left</drop_query>
|
|
<drop_query>DROP TABLE IF EXISTS phj_asof_right</drop_query>
|
|
</test>
|