2019-01-25 15:42:24 +00:00
|
|
|
#include <iostream>
|
|
|
|
|
2018-03-04 16:15:31 +00:00
|
|
|
#include <Common/typeid_cast.h>
|
|
|
|
#include <Storages/IStorage.h>
|
2019-01-25 15:42:24 +00:00
|
|
|
#include <Interpreters/IdentifierSemantic.h>
|
2019-12-18 03:56:03 +00:00
|
|
|
#include <Interpreters/InterpreterSelectQuery.h>
|
|
|
|
#include <Interpreters/PredicateExpressionsOptimizer.h>
|
2018-03-04 16:15:31 +00:00
|
|
|
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
2019-01-25 15:42:24 +00:00
|
|
|
#include <Parsers/IAST.h>
|
|
|
|
#include <Parsers/ASTFunction.h>
|
|
|
|
#include <Parsers/ASTIdentifier.h>
|
|
|
|
#include <Parsers/ASTSelectQuery.h>
|
|
|
|
#include <Parsers/ASTSelectWithUnionQuery.h>
|
|
|
|
#include <Parsers/ASTSubquery.h>
|
|
|
|
#include <Parsers/ASTTablesInSelectQuery.h>
|
2018-08-22 06:42:37 +00:00
|
|
|
#include <Parsers/queryToString.h>
|
2019-01-25 15:42:24 +00:00
|
|
|
#include <Interpreters/Context.h>
|
|
|
|
#include <Interpreters/ExpressionActions.h>
|
2018-09-12 05:41:09 +00:00
|
|
|
#include <Interpreters/QueryNormalizer.h>
|
2018-09-28 10:52:08 +00:00
|
|
|
#include <Interpreters/QueryAliasesVisitor.h>
|
2019-10-23 13:59:03 +00:00
|
|
|
#include <Interpreters/MarkTableIdentifiersVisitor.h>
|
2019-01-30 02:47:26 +00:00
|
|
|
#include <Interpreters/TranslateQualifiedNamesVisitor.h>
|
2019-12-18 03:56:03 +00:00
|
|
|
#include <Interpreters/PredicateRewriteVisitor.h>
|
2019-12-12 15:28:24 +00:00
|
|
|
#include <Interpreters/getTableExpressions.h>
|
2019-12-18 03:56:03 +00:00
|
|
|
#include <Interpreters/ExtractExpressionInfoVisitor.h>
|
2019-01-30 02:47:26 +00:00
|
|
|
#include <Functions/FunctionFactory.h>
|
2019-07-16 20:05:00 +00:00
|
|
|
|
2018-03-04 16:15:31 +00:00
|
|
|
|
|
|
|
namespace DB
|
|
|
|
{
|
|
|
|
|
2019-01-09 15:44:20 +00:00
|
|
|
namespace ErrorCodes
|
|
|
|
{
|
|
|
|
extern const int LOGICAL_ERROR;
|
|
|
|
extern const int UNKNOWN_ELEMENT_IN_AST;
|
|
|
|
}
|
|
|
|
|
2018-03-04 16:15:31 +00:00
|
|
|
PredicateExpressionsOptimizer::PredicateExpressionsOptimizer(
|
2019-12-18 03:56:03 +00:00
|
|
|
const Context & context_, const TablesWithColumnNames & tables_with_columns_, const Settings & settings_)
|
|
|
|
: context(context_), tables_with_columns(tables_with_columns_), settings(settings_)
|
2018-03-04 16:15:31 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
bool PredicateExpressionsOptimizer::optimize(ASTSelectQuery & select_query)
|
2018-03-04 16:15:31 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
if (!settings.enable_optimize_predicate_expression || !select_query.tables() || select_query.tables()->children.empty())
|
2018-03-04 16:15:31 +00:00
|
|
|
return false;
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
if ((!select_query.where() && !select_query.prewhere()) || select_query.array_join_expression_list())
|
2018-11-15 15:23:44 +00:00
|
|
|
return false;
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
const auto & tables_predicates = extractTablesPredicates(select_query.where(), select_query.prewhere());
|
2019-04-18 10:39:25 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
if (!tables_predicates.empty())
|
|
|
|
return tryRewritePredicatesToTables(select_query.refTables()->children, tables_predicates);
|
2018-03-04 16:15:31 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
return false;
|
2018-03-04 16:15:31 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
static ASTs splitConjunctionPredicate(const std::initializer_list<const ASTPtr> & predicates)
|
2018-03-04 16:15:31 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
std::vector<ASTPtr> res;
|
2018-03-04 16:15:31 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
auto remove_expression_at_index = [&res] (const size_t index)
|
|
|
|
{
|
|
|
|
if (index < res.size() - 1)
|
|
|
|
std::swap(res[index], res.back());
|
|
|
|
res.pop_back();
|
|
|
|
};
|
2018-08-22 06:42:37 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
for (const auto & predicate : predicates)
|
2018-03-04 16:15:31 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
if (!predicate)
|
2018-09-12 05:41:09 +00:00
|
|
|
continue;
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
res.emplace_back(predicate);
|
2018-03-04 16:15:31 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
for (size_t idx = 0; idx < res.size();)
|
2018-03-04 16:15:31 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
const auto & expression = res.at(idx);
|
|
|
|
|
|
|
|
if (const auto * function = expression->as<ASTFunction>(); function && function->name == "and")
|
2018-03-04 16:15:31 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
for (auto & child : function->arguments->children)
|
|
|
|
res.emplace_back(child);
|
|
|
|
|
|
|
|
remove_expression_at_index(idx);
|
|
|
|
continue;
|
2018-03-04 16:15:31 +00:00
|
|
|
}
|
2019-12-18 03:56:03 +00:00
|
|
|
++idx;
|
2018-03-04 16:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
2019-12-18 03:56:03 +00:00
|
|
|
|
|
|
|
return res;
|
2018-03-04 16:15:31 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
std::vector<ASTs> PredicateExpressionsOptimizer::extractTablesPredicates(const ASTPtr & where, const ASTPtr & prewhere)
|
2019-01-30 02:47:26 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
std::vector<ASTs> tables_predicates(tables_with_columns.size());
|
|
|
|
|
|
|
|
for (const auto & predicate_expression : splitConjunctionPredicate({where, prewhere}))
|
2019-01-30 02:47:26 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
ExpressionInfoVisitor::Data expression_info{.context = context, .tables = tables_with_columns};
|
|
|
|
ExpressionInfoVisitor(expression_info).visit(predicate_expression);
|
2019-01-30 02:47:26 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
if (expression_info.is_stateful_function)
|
|
|
|
return {}; /// give up the optimization when the predicate contains stateful function
|
2019-02-15 08:03:18 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
if (!expression_info.is_array_join)
|
|
|
|
{
|
|
|
|
if (expression_info.unique_reference_tables_pos.size() == 1)
|
|
|
|
tables_predicates[*expression_info.unique_reference_tables_pos.begin()].emplace_back(predicate_expression);
|
|
|
|
else if (expression_info.unique_reference_tables_pos.size() == 0)
|
|
|
|
{
|
|
|
|
for (size_t index = 0; index < tables_predicates.size(); ++index)
|
|
|
|
tables_predicates[index].emplace_back(predicate_expression);
|
|
|
|
}
|
2019-01-30 02:47:26 +00:00
|
|
|
}
|
2019-04-18 10:39:25 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
return tables_predicates; /// everything is OK, it can be optimized
|
|
|
|
}
|
|
|
|
|
|
|
|
bool PredicateExpressionsOptimizer::tryRewritePredicatesToTables(ASTs & tables_element, const std::vector<ASTs> & tables_predicates)
|
|
|
|
{
|
|
|
|
bool is_rewrite_tables = false;
|
2019-01-30 02:47:26 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
for (size_t index = tables_element.size(); index > 0; --index)
|
2019-04-18 10:39:25 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
size_t table_pos = index - 1;
|
2019-04-18 10:39:25 +00:00
|
|
|
|
|
|
|
/// NOTE: the syntactic way of pushdown has limitations and should be partially disabled in case of JOINs.
|
|
|
|
/// Let's take a look at the query:
|
|
|
|
///
|
|
|
|
/// SELECT a, b FROM (SELECT 1 AS a) ANY LEFT JOIN (SELECT 1 AS a, 1 AS b) USING (a) WHERE b = 0
|
|
|
|
///
|
|
|
|
/// The result is empty - without pushdown. But the pushdown tends to modify it in this way:
|
|
|
|
///
|
|
|
|
/// SELECT a, b FROM (SELECT 1 AS a) ANY LEFT JOIN (SELECT 1 AS a, 1 AS b WHERE b = 0) USING (a) WHERE b = 0
|
|
|
|
///
|
|
|
|
/// That leads to the empty result in the right subquery and changes the whole outcome to (1, 0) or (1, NULL).
|
|
|
|
/// It happens because the not-matching columns are replaced with a global default values on JOIN.
|
|
|
|
/// Same is true for RIGHT JOIN and FULL JOIN.
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
if (const auto & table_element = tables_element[table_pos]->as<ASTTablesInSelectQueryElement>())
|
2019-04-18 10:39:25 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
if (table_element->table_join && isLeft(table_element->table_join->as<ASTTableJoin>()->kind))
|
|
|
|
continue; /// Skip right table optimization
|
2019-01-30 02:47:26 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
if (table_element->table_join && isFull(table_element->table_join->as<ASTTableJoin>()->kind))
|
|
|
|
break; /// Skip left and right table optimization
|
2018-03-04 16:15:31 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
is_rewrite_tables |= tryRewritePredicatesToTable(tables_element[table_pos], tables_predicates[table_pos],
|
|
|
|
tables_with_columns[table_pos].columns);
|
2018-03-04 16:15:31 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
if (table_element->table_join && isRight(table_element->table_join->as<ASTTableJoin>()->kind))
|
|
|
|
break; /// Skip left table optimization
|
2018-03-04 16:15:31 +00:00
|
|
|
}
|
|
|
|
}
|
2019-01-25 15:42:24 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
return is_rewrite_tables;
|
2018-03-04 16:15:31 +00:00
|
|
|
}
|
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
bool PredicateExpressionsOptimizer::tryRewritePredicatesToTable(ASTPtr & table_element, const ASTs & table_predicates, const Names & table_column) const
|
2019-01-25 15:42:24 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
if (!table_predicates.empty())
|
2019-01-25 15:42:24 +00:00
|
|
|
{
|
2019-12-18 03:56:03 +00:00
|
|
|
PredicateRewriteVisitor::Data data(
|
|
|
|
context, table_predicates, table_column, settings.enable_optimize_predicate_expression_to_final_subquery);
|
2019-01-25 15:42:24 +00:00
|
|
|
|
2019-12-18 03:56:03 +00:00
|
|
|
PredicateRewriteVisitor(data).visit(table_element);
|
|
|
|
return data.isRewrite();
|
2018-09-12 05:41:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-03-04 16:15:31 +00:00
|
|
|
}
|