mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-21 01:00:48 +00:00
MergeTreeWhereOptimizer supports constant tuple in both sides of equals
This commit is contained in:
parent
64ffacd9e0
commit
23ce41e3bb
@ -824,7 +824,7 @@ MergeTreeDataSelectAnalysisResultPtr ReadFromMergeTree::selectRangesToRead(
|
||||
return std::make_shared<MergeTreeDataSelectAnalysisResult>(MergeTreeDataSelectAnalysisResult{
|
||||
.result = std::make_exception_ptr(Exception(
|
||||
ErrorCodes::INDEX_NOT_USED,
|
||||
"Primary key ({}) is not used and setting 'force_primary_key' is set.",
|
||||
"Primary key ({}) is not used and setting 'force_primary_key' is set",
|
||||
fmt::join(primary_key_columns, ", ")))});
|
||||
}
|
||||
LOG_DEBUG(log, "Key condition: {}", key_condition.toString());
|
||||
|
@ -119,41 +119,50 @@ static bool isConditionGood(const ASTPtr & condition)
|
||||
return false;
|
||||
}
|
||||
|
||||
static const ASTFunction * getAsTuple(const ASTPtr & node)
|
||||
{
|
||||
if (const auto * func = node->as<ASTFunction>(); func && func->name == "tuple")
|
||||
return func;
|
||||
return {};
|
||||
};
|
||||
|
||||
static bool getAsTupleLiteral(const ASTPtr & node, Tuple & tuple)
|
||||
{
|
||||
if (const auto * value_tuple = node->as<ASTLiteral>())
|
||||
return value_tuple && value_tuple->value.tryGet<Tuple>(tuple);
|
||||
return false;
|
||||
};
|
||||
|
||||
bool MergeTreeWhereOptimizer::tryAnalyzeTuple(Conditions & res, const ASTFunction * func, bool is_final) const
|
||||
{
|
||||
if (!func || func->name != "equals" || func->arguments->children.empty())
|
||||
if (!func || func->name != "equals" || func->arguments->children.size() != 2)
|
||||
return false;
|
||||
|
||||
const auto * func_tuple = func->arguments->children[0]->as<ASTFunction>();
|
||||
if (!func_tuple || func_tuple->name != "tuple")
|
||||
Tuple tuple_lit;
|
||||
const ASTFunction * tuple_other = nullptr;
|
||||
if (getAsTupleLiteral(func->arguments->children[0], tuple_lit))
|
||||
tuple_other = getAsTuple(func->arguments->children[1]);
|
||||
else if (getAsTupleLiteral(func->arguments->children[1], tuple_lit))
|
||||
tuple_other = getAsTuple(func->arguments->children[0]);
|
||||
|
||||
if (!tuple_other || tuple_lit.size() != tuple_other->arguments->children.size())
|
||||
return false;
|
||||
|
||||
if (func->arguments->children.size() <= 1)
|
||||
return false;
|
||||
|
||||
Tuple tuple;
|
||||
{
|
||||
const auto * value_tuple = func->arguments->children[1]->as<ASTLiteral>();
|
||||
if (!value_tuple || !value_tuple->value.tryGet<Tuple>(tuple))
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (const auto & child : func_tuple->arguments->children)
|
||||
for (size_t i = 0; i < tuple_lit.size(); ++i)
|
||||
{
|
||||
const auto & child = tuple_other->arguments->children[i];
|
||||
std::shared_ptr<IAST> fetch_sign_column = nullptr;
|
||||
/// tuple in tuple like (a, (b, c)) = (1, (2, 3))
|
||||
if (const auto * child_func = child->as<ASTFunction>(); child_func && child_func->name == "tuple")
|
||||
if (const auto * child_func = getAsTuple(child))
|
||||
fetch_sign_column = std::make_shared<ASTFunction>(*child_func);
|
||||
else if (const auto * child_ident = child->as<ASTIdentifier>())
|
||||
fetch_sign_column = std::make_shared<ASTIdentifier>(child_ident->name());
|
||||
else
|
||||
return false;
|
||||
|
||||
ASTPtr fetch_sign_value = std::make_shared<ASTLiteral>(tuple.at(index));
|
||||
ASTPtr fetch_sign_value = std::make_shared<ASTLiteral>(tuple_lit.at(i));
|
||||
ASTPtr func_node = makeASTFunction("equals", fetch_sign_column, fetch_sign_value);
|
||||
analyzeImpl(res, func_node, is_final);
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -1,2 +1,5 @@
|
||||
1 A 2021-01-01
|
||||
1 A 2021-01-01
|
||||
1 A 2021-01-01
|
||||
1 A 2021-01-01
|
||||
1 A 2021-01-01
|
||||
|
@ -5,17 +5,22 @@ CREATE TABLE test_tuple_filter (id UInt32, value String, log_date Date) Engine=M
|
||||
INSERT INTO test_tuple_filter VALUES (1, 'A','2021-01-01'),(2,'B','2021-01-01'),(3,'C','2021-01-01'),(4,'D','2021-01-02'),(5,'E','2021-01-02');
|
||||
|
||||
SET force_primary_key = 1;
|
||||
|
||||
SELECT * FROM test_tuple_filter WHERE (id, value) = (1, 'A');
|
||||
SELECT * FROM test_tuple_filter WHERE (1, 'A') = (id, value);
|
||||
|
||||
-- not implemented yet
|
||||
SELECT * FROM test_tuple_filter WHERE (1, value) = (id, 'A'); -- { serverError INDEX_NOT_USED }
|
||||
|
||||
SET force_index_by_date = 1;
|
||||
SET force_primary_key = 0;
|
||||
SELECT * FROM test_tuple_filter WHERE (log_date, value) = ('2021-01-01', 'A');
|
||||
|
||||
|
||||
SET force_index_by_date = 0;
|
||||
SET force_primary_key = 0;
|
||||
|
||||
SELECT * FROM test_tuple_filter WHERE tuple(id) = tuple(1) FORMAT Null;
|
||||
SELECT * FROM test_tuple_filter WHERE (1, value) = (id, 'A');
|
||||
SELECT * FROM test_tuple_filter WHERE tuple(id) = tuple(1);
|
||||
SELECT * FROM test_tuple_filter WHERE (log_date, value) = tuple('2021-01-01'); -- { serverError 43 }
|
||||
SELECT * FROM test_tuple_filter WHERE (id, value) = tuple(1); -- { serverError 43 }
|
||||
SELECT * FROM test_tuple_filter WHERE tuple(id, value) = tuple(value, id); -- { serverError 386 }
|
||||
|
Loading…
Reference in New Issue
Block a user