From 7ffe1ae0bc0e97db987020c59c35604938b51cf5 Mon Sep 17 00:00:00 2001 From: Pablo Alegre Date: Wed, 11 May 2022 18:27:47 +0200 Subject: [PATCH 1/2] Remove unnecesary SELECT * FROM () --- .../UnionSelectOptimizerVisitor.cpp | 160 ++++++++++++++++++ .../UnionSelectOptimizerVisitor.h | 28 +++ src/Interpreters/executeQuery.cpp | 2 + 3 files changed, 190 insertions(+) create mode 100644 src/Interpreters/UnionSelectOptimizerVisitor.cpp create mode 100644 src/Interpreters/UnionSelectOptimizerVisitor.h diff --git a/src/Interpreters/UnionSelectOptimizerVisitor.cpp b/src/Interpreters/UnionSelectOptimizerVisitor.cpp new file mode 100644 index 000000000000..9c4b76dcf921 --- /dev/null +++ b/src/Interpreters/UnionSelectOptimizerVisitor.cpp @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include +#include +#include + +/* +option a) +┌─explain─────────────────────────────────────┐ +│ SelectWithUnionQuery (children 1) │ <- Replace this node +│ ExpressionList (children 1) │ +│ SelectQuery (children 2) │ +│ ExpressionList (children 1) │ +│ Asterisk │ +│ TablesInSelectQuery (children 1) │ +│ TablesInSelectQueryElement (children 1) │ +│ TableExpression (children 1) │ +│ Subquery (children 1) │ +│ SelectWithUnionQuery (children 1) │ <- with this one +│ (whatever) │ +└─────────────────────────────────────────────┘ + +option b) +┌─explain─────────────────────────────────────┐ +│ SelectWithUnionQuery (children 1) │ +│ ExpressionList (children 2) │ +│ SelectQuery (children 2) │ <- Replace this node +│ ExpressionList (children 1) │ +│ Asterisk │ +│ TablesInSelectQuery (children 1) │ +│ TablesInSelectQueryElement (children 1) │ +│ TableExpression (children 1) │ +│ Subquery (children 1) │ +│ SelectWithUnionQuery (children 1) │ +│ ExpressionList (children 1) │ +│ SelectQuery (children 1) │ <- with this one +│ ExpressionList (children 1) │ +│ Literal UInt64_1 (alias n) │ +│ SelectQuery (children 2) │ +│ ExpressionList (children 1) │ +│ Asterisk │ +│ TablesInSelectQuery (children 1) │ +│ TablesInSelectQueryElement (children 1) │ +│ TableExpression (children 1) │ +│ Subquery (children 1) │ +│ SelectWithUnionQuery (children 1) │ +│ ExpressionList (children 1) │ +│ SelectQuery (children 1) │ +│ ExpressionList (children 1) │ +│ Literal UInt64_2 (alias n) │ +└─────────────────────────────────────────────┘ + + +*/ +namespace DB +{ + +void UnionSelectOptimizerVisitor::visit(ASTPtr & ast) +{ + if (ast->as() || ast->as()) + while (visit_replace(ast)) + ; + + for (ASTPtr & child : ast->children) + visit(child); +} + +bool UnionSelectOptimizerVisitor::visit_replace(DB::ASTPtr & node) +{ + DB::ASTPtr query; + DB::ASTPtr next = node; + if (next->as()) + { + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + for (DB::ASTPtr & child : next->children) + { + if (child->as()) + { + next = child; + if (!move_next(next)) + return false; + continue; + } + if (child->as()) + { + next = child; + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + query = next; + continue; + } + else + return false; + } + } + else if (next->as()) + { + if (next->children.size() != 2) + return false; + + for (DB::ASTPtr & child : next->children) + { + if (child->as()) + { + next = child; + if (!move_next(next)) + return false; + continue; + } + if (child->as()) + { + next = child; + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + if (!move_next(next)) + return false; + + query = next; + continue; + } + else + return false; + } + } + + node.swap(query); + return true; +} + +} diff --git a/src/Interpreters/UnionSelectOptimizerVisitor.h b/src/Interpreters/UnionSelectOptimizerVisitor.h new file mode 100644 index 000000000000..f7c2e967612a --- /dev/null +++ b/src/Interpreters/UnionSelectOptimizerVisitor.h @@ -0,0 +1,28 @@ +#pragma once + +#include + +namespace DB +{ + +struct UnionSelectOptimizerVisitor +{ +public: + static void visit(ASTPtr & ast); + +private: + template + static bool move_next(DB::ASTPtr & item) + { + if (item->children.size() != 1 || !item->children.at(0)->as()) + { + return false; + } + item = item->children.at(0); + return true; + } + + + static bool visit_replace(ASTPtr & node); +}; +} diff --git a/src/Interpreters/executeQuery.cpp b/src/Interpreters/executeQuery.cpp index d1596c083187..cbf3d6cbd086 100644 --- a/src/Interpreters/executeQuery.cpp +++ b/src/Interpreters/executeQuery.cpp @@ -68,6 +68,7 @@ #include #include +#include namespace ProfileEvents @@ -440,6 +441,7 @@ static std::tuple executeQueryImpl( /// TODO: parser should fail early when max_query_size limit is reached. ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth); + UnionSelectOptimizerVisitor::visit(ast); if (auto txn = context->getCurrentTransaction()) { From 1a78b7f49ecb2aa6b35c00abc247602f6a3628fd Mon Sep 17 00:00:00 2001 From: Pablo Alegre Date: Thu, 12 May 2022 13:18:39 +0200 Subject: [PATCH 2/2] Add setting remove_redundant_select_asterisk_from --- src/Core/Settings.h | 2 ++ src/Interpreters/executeQuery.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Core/Settings.h b/src/Core/Settings.h index 30e01413e1be..2d45c435b034 100644 --- a/src/Core/Settings.h +++ b/src/Core/Settings.h @@ -578,6 +578,8 @@ static constexpr UInt64 operator""_Gb(unsigned long long value) \ M(Bool, allow_unrestricted_reads_from_keeper, false, "Allow unrestricted (without condition on path) reads from system.zookeeper table, can be handy, but is not safe for zookeeper", 0) \ \ + M(Bool, remove_redundant_select_asterisk_from, true, "Remove reduntant SELECT * FROM () in the query/subqueries", 0) \ + \ /** Experimental functions */ \ M(Bool, allow_experimental_funnel_functions, false, "Enable experimental functions for funnel analysis.", 0) \ M(Bool, allow_experimental_nlp_functions, false, "Enable experimental functions for natural language processing.", 0) \ diff --git a/src/Interpreters/executeQuery.cpp b/src/Interpreters/executeQuery.cpp index cbf3d6cbd086..0d5d564bd811 100644 --- a/src/Interpreters/executeQuery.cpp +++ b/src/Interpreters/executeQuery.cpp @@ -441,7 +441,6 @@ static std::tuple executeQueryImpl( /// TODO: parser should fail early when max_query_size limit is reached. ast = parseQuery(parser, begin, end, "", max_query_size, settings.max_parser_depth); - UnionSelectOptimizerVisitor::visit(ast); if (auto txn = context->getCurrentTransaction()) { @@ -569,6 +568,12 @@ static std::tuple executeQueryImpl( NormalizeSelectWithUnionQueryVisitor{data}.visit(ast); } + /// Remove redundant queries + if (settings.remove_redundant_select_asterisk_from) + { + UnionSelectOptimizerVisitor::visit(ast); + } + /// Check the limits. checkASTSizeLimits(*ast, settings);