MergeTreeWhereOptimizer supports constant tuple in both sides of equals

This commit is contained in:
vdimir 2021-09-28 17:44:33 +03:00
parent 64ffacd9e0
commit 23ce41e3bb
No known key found for this signature in database
GPG Key ID: 9B404D301C0CC7EB
4 changed files with 38 additions and 21 deletions

View File

@ -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());

View File

@ -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;

View File

@ -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

View File

@ -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 }