Skip to content

Commit 7d50e5d

Browse files
authored
Merge pull request ClickHouse#80597 from zoomxi/keycondition_improve
Enable binary search for wrapped primary keys with always monotonic function chains
2 parents aa02e42 + e391ff2 commit 7d50e5d

File tree

3 files changed

+73
-3
lines changed

3 files changed

+73
-3
lines changed

src/Storages/MergeTree/KeyCondition.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2892,9 +2892,41 @@ std::optional<Range> KeyCondition::applyMonotonicFunctionsChainToRange(
28922892
// This allows to use a more efficient lookup with no extra reads.
28932893
bool KeyCondition::matchesExactContinuousRange() const
28942894
{
2895-
// Not implemented yet.
2896-
if (hasMonotonicFunctionsChain())
2897-
return false;
2895+
const Field field{};
2896+
auto is_always_monotonic_chain = [&field](const std::vector<FunctionBasePtr> & chain)
2897+
{
2898+
for (const auto & func : chain)
2899+
{
2900+
if (!func || !func->hasInformationAboutMonotonicity())
2901+
return false;
2902+
2903+
const auto & types = func->getArgumentTypes();
2904+
if (types.empty() || !types.front())
2905+
return false;
2906+
2907+
const auto monotonicity = func->getMonotonicityForRange(*types.front(), field, field);
2908+
if (!monotonicity.is_always_monotonic)
2909+
return false;
2910+
}
2911+
2912+
return true;
2913+
};
2914+
2915+
for (const auto & elem : rpn)
2916+
{
2917+
if (!elem.monotonic_functions_chain.empty() && !is_always_monotonic_chain(elem.monotonic_functions_chain))
2918+
return false;
2919+
2920+
if (elem.set_index)
2921+
{
2922+
if (elem.function != RPNElement::Function::FUNCTION_IN_SET || elem.set_index->size() != 1)
2923+
return false;
2924+
2925+
for (const auto & mapping : elem.set_index->getIndexesMapping())
2926+
if (!mapping.functions.empty() && !is_always_monotonic_chain(mapping.functions))
2927+
return false;
2928+
}
2929+
}
28982930

28992931
enum Constraint
29002932
{
@@ -2936,6 +2968,11 @@ bool KeyCondition::matchesExactContinuousRange() const
29362968
continue;
29372969
}
29382970

2971+
if (element.function == RPNElement::Function::ALWAYS_TRUE)
2972+
{
2973+
continue;
2974+
}
2975+
29392976
return false;
29402977
}
29412978

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
3
2+
1
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/usr/bin/env bash
2+
3+
CUR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
4+
# shellcheck source=../shell_config.sh
5+
. "$CUR_DIR"/../shell_config.sh
6+
7+
$CLICKHOUSE_CLIENT -n -q "
8+
DROP TABLE IF EXISTS t;
9+
CREATE TABLE t
10+
(
11+
c Enum8('Zero' = 0, 'One' = 1, 'Two' = 2, 'Three' = 3, 'Four' = 4, 'Five' = 5)
12+
)
13+
ENGINE = MergeTree
14+
ORDER BY c;
15+
INSERT INTO t values('One');
16+
SELECT * FROM t WHERE c = 1 settings send_logs_level='trace';
17+
SELECT * FROM t WHERE c = 'One' settings send_logs_level='trace';
18+
SELECT * FROM t WHERE c = 1 and 1 = 1 settings send_logs_level='trace';
19+
" 2>&1 | grep -c "binary search"
20+
21+
$CLICKHOUSE_CLIENT -n -q "
22+
DROP TABLE IF EXISTS t1;
23+
CREATE TABLE t1
24+
(
25+
timestamp DateTime64(3, 'Asia/Shanghai')
26+
)
27+
ENGINE = MergeTree
28+
ORDER BY timestamp;
29+
INSERT INTO t1 VALUES ('2025-05-21 00:00:00');
30+
SELECT * FROM t1 WHERE toDayOfMonth(timestamp) = 1 settings send_logs_level='trace';
31+
" 2>&1 | grep -c "generic exclusion search"

0 commit comments

Comments
 (0)