Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Core/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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) \
Expand Down
160 changes: 160 additions & 0 deletions src/Interpreters/UnionSelectOptimizerVisitor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
#include <Interpreters/UnionSelectOptimizerVisitor.h>
#include <Parsers/ASTAsterisk.h>
#include <Parsers/ASTExpressionList.h>
#include <Parsers/ASTSelectQuery.h>
#include <Parsers/ASTSelectWithUnionQuery.h>
#include <Parsers/ASTSubquery.h>
#include <Parsers/ASTTablesInSelectQuery.h>

/*
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<ASTSelectWithUnionQuery>() || ast->as<ASTSelectQuery>())
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<DB::ASTSelectWithUnionQuery>())
{
if (!move_next<DB::ASTExpressionList>(next))
return false;

if (!move_next<DB::ASTSelectQuery>(next))
return false;

for (DB::ASTPtr & child : next->children)
{
if (child->as<DB::ASTExpressionList>())
{
next = child;
if (!move_next<DB::ASTAsterisk>(next))
return false;
continue;
}
if (child->as<DB::ASTTablesInSelectQuery>())
{
next = child;
if (!move_next<DB::ASTTablesInSelectQueryElement>(next))
return false;

if (!move_next<DB::ASTTableExpression>(next))
return false;

if (!move_next<DB::ASTSubquery>(next))
return false;

if (!move_next<DB::ASTSelectWithUnionQuery>(next))
return false;

query = next;
continue;
}
else
return false;
}
}
else if (next->as<DB::ASTSelectQuery>())
{
if (next->children.size() != 2)
return false;

for (DB::ASTPtr & child : next->children)
{
if (child->as<DB::ASTExpressionList>())
{
next = child;
if (!move_next<DB::ASTAsterisk>(next))
return false;
continue;
}
if (child->as<DB::ASTTablesInSelectQuery>())
{
next = child;
if (!move_next<DB::ASTTablesInSelectQueryElement>(next))
return false;

if (!move_next<DB::ASTTableExpression>(next))
return false;

if (!move_next<DB::ASTSubquery>(next))
return false;

if (!move_next<DB::ASTSelectWithUnionQuery>(next))
return false;

if (!move_next<DB::ASTExpressionList>(next))
return false;

if (!move_next<DB::ASTSelectQuery>(next))
return false;

query = next;
continue;
}
else
return false;
}
}

node.swap(query);
return true;
}

}
28 changes: 28 additions & 0 deletions src/Interpreters/UnionSelectOptimizerVisitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#pragma once

#include <Parsers/IAST.h>

namespace DB
{

struct UnionSelectOptimizerVisitor
{
public:
static void visit(ASTPtr & ast);

private:
template <typename T>
static bool move_next(DB::ASTPtr & item)
{
if (item->children.size() != 1 || !item->children.at(0)->as<T>())
{
return false;
}
item = item->children.at(0);
return true;
}


static bool visit_replace(ASTPtr & node);
};
}
7 changes: 7 additions & 0 deletions src/Interpreters/executeQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#include <base/demangle.h>

#include <random>
#include <Interpreters/UnionSelectOptimizerVisitor.h>


namespace ProfileEvents
Expand Down Expand Up @@ -567,6 +568,12 @@ static std::tuple<ASTPtr, BlockIO> executeQueryImpl(
NormalizeSelectWithUnionQueryVisitor{data}.visit(ast);
}

/// Remove redundant queries
if (settings.remove_redundant_select_asterisk_from)
{
UnionSelectOptimizerVisitor::visit(ast);
}

/// Check the limits.
checkASTSizeLimits(*ast, settings);

Expand Down