mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-18 13:42:02 +00:00
Remove redundant group by keys with constants
This commit is contained in:
parent
821c55463f
commit
fff9fd4f00
@ -42,22 +42,29 @@ public:
|
|||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
struct NodeWithInfo
|
||||||
|
{
|
||||||
|
QueryTreeNodePtr node;
|
||||||
|
bool parents_are_only_deterministic;
|
||||||
|
};
|
||||||
|
|
||||||
static bool canBeEliminated(QueryTreeNodePtr & node, const QueryTreeNodePtrWithHashSet & group_by_keys)
|
static bool canBeEliminated(QueryTreeNodePtr & node, const QueryTreeNodePtrWithHashSet & group_by_keys)
|
||||||
{
|
{
|
||||||
auto * function = node->as<FunctionNode>();
|
auto * function = node->as<FunctionNode>();
|
||||||
if (!function || function->getArguments().getNodes().empty())
|
if (!function || function->getArguments().getNodes().empty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QueryTreeNodes candidates;
|
std::vector<NodeWithInfo> candidates;
|
||||||
auto & function_arguments = function->getArguments().getNodes();
|
auto & function_arguments = function->getArguments().getNodes();
|
||||||
|
bool is_deterministic = function->getFunction()->isDeterministicInScopeOfQuery();
|
||||||
for (auto it = function_arguments.rbegin(); it != function_arguments.rend(); ++it)
|
for (auto it = function_arguments.rbegin(); it != function_arguments.rend(); ++it)
|
||||||
candidates.push_back(*it);
|
candidates.push_back({ *it, is_deterministic });
|
||||||
|
|
||||||
// Using DFS we traverse function tree and try to find if it uses other keys as function arguments.
|
// Using DFS we traverse function tree and try to find if it uses other keys as function arguments.
|
||||||
// TODO: Also process CONSTANT here. We can simplify GROUP BY x, x + 1 to GROUP BY x.
|
// TODO: Also process CONSTANT here. We can simplify GROUP BY x, x + 1 to GROUP BY x.
|
||||||
while (!candidates.empty())
|
while (!candidates.empty())
|
||||||
{
|
{
|
||||||
auto candidate = candidates.back();
|
auto [candidate, deterministic_context] = candidates.back();
|
||||||
candidates.pop_back();
|
candidates.pop_back();
|
||||||
|
|
||||||
bool found = group_by_keys.contains(candidate);
|
bool found = group_by_keys.contains(candidate);
|
||||||
@ -73,8 +80,9 @@ private:
|
|||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
|
bool is_deterministic_function = deterministic_context && function->getFunction()->isDeterministicInScopeOfQuery();
|
||||||
for (auto it = arguments.rbegin(); it != arguments.rend(); ++it)
|
for (auto it = arguments.rbegin(); it != arguments.rend(); ++it)
|
||||||
candidates.push_back(*it);
|
candidates.push_back({ *it, is_deterministic_function });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -82,6 +90,10 @@ private:
|
|||||||
if (!found)
|
if (!found)
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case QueryTreeNodeType::CONSTANT:
|
||||||
|
if (!deterministic_context)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -246,3 +246,40 @@ QUERY id: 0, group_by_type: grouping_sets
|
|||||||
ARGUMENTS
|
ARGUMENTS
|
||||||
LIST id: 53, nodes: 1
|
LIST id: 53, nodes: 1
|
||||||
COLUMN id: 54, column_name: number, result_type: UInt64, source_id: 11
|
COLUMN id: 54, column_name: number, result_type: UInt64, source_id: 11
|
||||||
|
QUERY id: 0, group_by_type: grouping_sets
|
||||||
|
PROJECTION COLUMNS
|
||||||
|
count() UInt64
|
||||||
|
PROJECTION
|
||||||
|
LIST id: 1, nodes: 1
|
||||||
|
FUNCTION id: 2, function_name: count, function_type: aggregate, result_type: UInt64
|
||||||
|
JOIN TREE
|
||||||
|
TABLE_FUNCTION id: 3, table_function_name: numbers
|
||||||
|
ARGUMENTS
|
||||||
|
LIST id: 4, nodes: 1
|
||||||
|
CONSTANT id: 5, constant_value: UInt64_1000, constant_value_type: UInt16
|
||||||
|
GROUP BY
|
||||||
|
LIST id: 6, nodes: 3
|
||||||
|
LIST id: 7, nodes: 1
|
||||||
|
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 3
|
||||||
|
LIST id: 9, nodes: 2
|
||||||
|
FUNCTION id: 10, function_name: modulo, function_type: ordinary, result_type: UInt8
|
||||||
|
ARGUMENTS
|
||||||
|
LIST id: 11, nodes: 2
|
||||||
|
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 3
|
||||||
|
CONSTANT id: 12, constant_value: UInt64_2, constant_value_type: UInt8
|
||||||
|
FUNCTION id: 13, function_name: modulo, function_type: ordinary, result_type: UInt8
|
||||||
|
ARGUMENTS
|
||||||
|
LIST id: 14, nodes: 2
|
||||||
|
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 3
|
||||||
|
CONSTANT id: 15, constant_value: UInt64_3, constant_value_type: UInt8
|
||||||
|
LIST id: 16, nodes: 2
|
||||||
|
FUNCTION id: 17, function_name: divide, function_type: ordinary, result_type: Float64
|
||||||
|
ARGUMENTS
|
||||||
|
LIST id: 18, nodes: 2
|
||||||
|
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 3
|
||||||
|
CONSTANT id: 19, constant_value: UInt64_2, constant_value_type: UInt8
|
||||||
|
FUNCTION id: 20, function_name: divide, function_type: ordinary, result_type: Float64
|
||||||
|
ARGUMENTS
|
||||||
|
LIST id: 21, nodes: 2
|
||||||
|
COLUMN id: 8, column_name: number, result_type: UInt64, source_id: 3
|
||||||
|
CONSTANT id: 22, constant_value: UInt64_3, constant_value_type: UInt8
|
||||||
|
@ -15,3 +15,12 @@ SELECT avg(log(2) * number) AS k FROM numbers(10000000)
|
|||||||
GROUP BY GROUPING SETS (((number % 2) * (number % 3), number % 3), (number % 2))
|
GROUP BY GROUPING SETS (((number % 2) * (number % 3), number % 3), (number % 2))
|
||||||
HAVING avg(log(2) * number) > 3465735.3
|
HAVING avg(log(2) * number) > 3465735.3
|
||||||
ORDER BY k;
|
ORDER BY k;
|
||||||
|
|
||||||
|
EXPLAIN QUERY TREE run_passes=1
|
||||||
|
SELECT count() FROM numbers(1000)
|
||||||
|
GROUP BY GROUPING SETS
|
||||||
|
(
|
||||||
|
(number, number + 1, number +2),
|
||||||
|
(number % 2, number % 3),
|
||||||
|
(number / 2, number / 3)
|
||||||
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user