mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-24 08:32:02 +00:00
Merge pull request #31218 from CurtizJ/map-contains-to-subcolumn
Optimize `mapContains` to reading of subcolumn
This commit is contained in:
commit
9538dcf0c7
@ -38,7 +38,13 @@ ASTPtr transformCountNullableToSubcolumn(const String & name_in_storage, const S
|
|||||||
return makeASTFunction("sum", makeASTFunction("not", ast));
|
return makeASTFunction("sum", makeASTFunction("not", ast));
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::unordered_map<String, std::tuple<TypeIndex, String, decltype(&transformToSubcolumn)>> function_to_subcolumn =
|
ASTPtr transformMapContainsToSubcolumn(const String & name_in_storage, const String & subcolumn_name, const ASTPtr & arg)
|
||||||
|
{
|
||||||
|
auto ast = transformToSubcolumn(name_in_storage, subcolumn_name);
|
||||||
|
return makeASTFunction("has", ast, arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::unordered_map<String, std::tuple<TypeIndex, String, decltype(&transformToSubcolumn)>> unary_function_to_subcolumn =
|
||||||
{
|
{
|
||||||
{"length", {TypeIndex::Array, "size0", transformToSubcolumn}},
|
{"length", {TypeIndex::Array, "size0", transformToSubcolumn}},
|
||||||
{"empty", {TypeIndex::Array, "size0", transformEmptyToSubcolumn}},
|
{"empty", {TypeIndex::Array, "size0", transformEmptyToSubcolumn}},
|
||||||
@ -50,31 +56,51 @@ const std::unordered_map<String, std::tuple<TypeIndex, String, decltype(&transfo
|
|||||||
{"mapValues", {TypeIndex::Map, "values", transformToSubcolumn}},
|
{"mapValues", {TypeIndex::Map, "values", transformToSubcolumn}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const std::unordered_map<String, std::tuple<TypeIndex, String, decltype(&transformMapContainsToSubcolumn)>> binary_function_to_subcolumn
|
||||||
|
{
|
||||||
|
{"mapContains", {TypeIndex::Map, "keys", transformMapContainsToSubcolumn}},
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RewriteFunctionToSubcolumnData::visit(ASTFunction & function, ASTPtr & ast) const
|
void RewriteFunctionToSubcolumnData::visit(ASTFunction & function, ASTPtr & ast) const
|
||||||
{
|
{
|
||||||
const auto & arguments = function.arguments->children;
|
const auto & arguments = function.arguments->children;
|
||||||
if (arguments.size() != 1)
|
if (arguments.empty() || arguments.size() > 2)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto * identifier = arguments[0]->as<ASTIdentifier>();
|
const auto * identifier = arguments[0]->as<ASTIdentifier>();
|
||||||
if (!identifier)
|
if (!identifier)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
auto it = function_to_subcolumn.find(function.name);
|
|
||||||
if (it == function_to_subcolumn.end())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto & [type_id, subcolumn_name, transformer] = it->second;
|
|
||||||
const auto & columns = metadata_snapshot->getColumns();
|
const auto & columns = metadata_snapshot->getColumns();
|
||||||
const auto & name_in_storage = identifier->name();
|
const auto & name_in_storage = identifier->name();
|
||||||
|
|
||||||
if (columns.has(name_in_storage)
|
if (!columns.has(name_in_storage))
|
||||||
&& columns.get(name_in_storage).type->getTypeId() == type_id)
|
return;
|
||||||
|
|
||||||
|
TypeIndex column_type_id = columns.get(name_in_storage).type->getTypeId();
|
||||||
|
|
||||||
|
if (arguments.size() == 1)
|
||||||
{
|
{
|
||||||
|
auto it = unary_function_to_subcolumn.find(function.name);
|
||||||
|
if (it != unary_function_to_subcolumn.end())
|
||||||
|
{
|
||||||
|
const auto & [type_id, subcolumn_name, transformer] = it->second;
|
||||||
|
if (column_type_id == type_id)
|
||||||
ast = transformer(name_in_storage, subcolumn_name);
|
ast = transformer(name_in_storage, subcolumn_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto it = binary_function_to_subcolumn.find(function.name);
|
||||||
|
if (it != binary_function_to_subcolumn.end())
|
||||||
|
{
|
||||||
|
const auto & [type_id, subcolumn_name, transformer] = it->second;
|
||||||
|
if (column_type_id == type_id)
|
||||||
|
ast = transformer(name_in_storage, subcolumn_name, arguments[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
4
tests/queries/0_stateless/02115_map_contains.reference
Normal file
4
tests/queries/0_stateless/02115_map_contains.reference
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
SELECT has(`m.keys`, \'a\')
|
||||||
|
FROM t_map_contains
|
||||||
|
1
|
||||||
|
0
|
12
tests/queries/0_stateless/02115_map_contains.sql
Normal file
12
tests/queries/0_stateless/02115_map_contains.sql
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
DROP TABLE IF EXISTS t_map_contains;
|
||||||
|
|
||||||
|
CREATE TABLE t_map_contains (m Map(String, UInt32)) ENGINE = Memory;
|
||||||
|
|
||||||
|
INSERT INTO t_map_contains VALUES (map('a', 1, 'b', 2)), (map('c', 3, 'd', 4));
|
||||||
|
|
||||||
|
SET optimize_functions_to_subcolumns = 1;
|
||||||
|
|
||||||
|
EXPLAIN SYNTAX SELECT mapContains(m, 'a') FROM t_map_contains;
|
||||||
|
SELECT mapContains(m, 'a') FROM t_map_contains;
|
||||||
|
|
||||||
|
DROP TABLE t_map_contains;
|
Loading…
Reference in New Issue
Block a user