mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-09-23 10:10:50 +00:00
dbms: Server: feature development [#METR-14875]
This commit is contained in:
parent
cd2d588418
commit
631d91325e
@ -15,10 +15,20 @@ struct LogicalOrWithLeftHandSide
|
|||||||
const std::string expression;
|
const std::string expression;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** Этот класс предоставляет функции для оптимизации логических выражений внутри запросов.
|
||||||
|
*
|
||||||
|
* Для простоты назовём однородной OR-цепочой любое выражение имеющее следующую структуру:
|
||||||
|
* expr = x1 OR ... OR expr = xN
|
||||||
|
* где expr - произвольное выражение и x1, ..., xN - литералы одного типа
|
||||||
|
*/
|
||||||
class LogicalExpressionsOptimizer
|
class LogicalExpressionsOptimizer
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
LogicalExpressionsOptimizer(ASTPtr root_);
|
LogicalExpressionsOptimizer(ASTPtr root_);
|
||||||
|
|
||||||
|
/** Заменить все довольно длинные однородные OR-цепочки expr = x1 OR ... OR expr = xN
|
||||||
|
* на выражения expr IN (x1, ..., xN).
|
||||||
|
*/
|
||||||
void optimizeDisjunctiveEqualityChains();
|
void optimizeDisjunctiveEqualityChains();
|
||||||
|
|
||||||
LogicalExpressionsOptimizer(const LogicalExpressionsOptimizer &) = delete;
|
LogicalExpressionsOptimizer(const LogicalExpressionsOptimizer &) = delete;
|
||||||
@ -26,25 +36,38 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
using Equalities = std::vector<ASTFunction *>;
|
using Equalities = std::vector<ASTFunction *>;
|
||||||
|
|
||||||
/// Цепочки x = c[1] OR x = c[2] OR ... x = C[N], где x - произвольное выражение
|
|
||||||
/// и c[1], c[2], ..., c[N] - литералы одного типа.
|
|
||||||
using DisjunctiveEqualitiesMap = std::map<LogicalOrWithLeftHandSide, Equalities>;
|
using DisjunctiveEqualitiesMap = std::map<LogicalOrWithLeftHandSide, Equalities>;
|
||||||
|
using DisjunctiveEqualityChain = DisjunctiveEqualitiesMap::value_type;
|
||||||
|
|
||||||
using ASTFunctionPtr = Poco::SharedPtr<ASTFunction>;
|
using ASTFunctionPtr = Poco::SharedPtr<ASTFunction>;
|
||||||
|
using IASTs = std::vector<IAST *>;
|
||||||
using ParentMap = std::map<ASTFunction *, std::vector<IAST *> >;
|
using ParentMap = std::map<ASTFunction *, IASTs>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// Собрать информацию про все равенства входящие в цепочки OR (не обязательно однородные).
|
||||||
void collectDisjunctiveEqualityChains();
|
void collectDisjunctiveEqualityChains();
|
||||||
|
|
||||||
|
/** Проверить, что множество равенств expr = x1, ..., expr = xN выполняет два следующих требования:
|
||||||
|
* 1. Оно не слишком маленькое
|
||||||
|
* 2. x1, ... xN имеют один и тот же тип
|
||||||
|
*/
|
||||||
bool mustTransform(const Equalities & equalities) const;
|
bool mustTransform(const Equalities & equalities) const;
|
||||||
ASTFunctionPtr createInExpression(const LogicalOrWithLeftHandSide & logical_or_with_lhs, const Equalities & equalities);
|
|
||||||
|
/// Создать новое выражение IN на основе цепочки OR.
|
||||||
|
ASTFunctionPtr createInExpression(const Equalities & equalities) const;
|
||||||
|
|
||||||
|
/// Вставить новое выражение IN в запрос.
|
||||||
|
void putInExpression(const DisjunctiveEqualityChain & chain, ASTFunctionPtr in_expression);
|
||||||
|
|
||||||
|
/// Удалить узлы OR, которые имеют только один узел типа Function.
|
||||||
void fixBrokenOrExpressions();
|
void fixBrokenOrExpressions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ASTPtr root;
|
ASTPtr root;
|
||||||
ASTSelectQuery * select_query;
|
ASTSelectQuery * select_query;
|
||||||
|
/// Информация про OR-цепочки внутри запроса.
|
||||||
DisjunctiveEqualitiesMap disjunctive_equalities_map;
|
DisjunctiveEqualitiesMap disjunctive_equalities_map;
|
||||||
|
// Родители функций OR.
|
||||||
ParentMap parent_map;
|
ParentMap parent_map;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -18,15 +18,16 @@ LogicalOrWithLeftHandSide::LogicalOrWithLeftHandSide(ASTFunction * or_function_,
|
|||||||
bool operator<(const LogicalOrWithLeftHandSide & lhs,
|
bool operator<(const LogicalOrWithLeftHandSide & lhs,
|
||||||
const LogicalOrWithLeftHandSide & rhs)
|
const LogicalOrWithLeftHandSide & rhs)
|
||||||
{
|
{
|
||||||
if (lhs.or_function < rhs.or_function)
|
std::ptrdiff_t res1 = lhs.or_function - rhs.or_function;
|
||||||
|
if (res1 < 0)
|
||||||
return true;
|
return true;
|
||||||
if (lhs.or_function > rhs.or_function)
|
if (res1 > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
int val = lhs.expression.compare(rhs.expression);
|
int res2 = lhs.expression.compare(rhs.expression);
|
||||||
if (val < 0)
|
if (res2 < 0)
|
||||||
return true;
|
return true;
|
||||||
if (val > 0)
|
if (res2 > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -42,46 +43,19 @@ void LogicalExpressionsOptimizer::optimizeDisjunctiveEqualityChains()
|
|||||||
if (select_query == nullptr)
|
if (select_query == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/** 1. Поиск всех цепочек OR.
|
|
||||||
*/
|
|
||||||
collectDisjunctiveEqualityChains();
|
collectDisjunctiveEqualityChains();
|
||||||
|
|
||||||
/** 2. Заменяем длинные цепочки на выражения IN.
|
for (const auto & chain : disjunctive_equalities_map)
|
||||||
*/
|
|
||||||
for (const auto & e : disjunctive_equalities_map)
|
|
||||||
{
|
{
|
||||||
const LogicalOrWithLeftHandSide & logical_or_with_lhs = e.first;
|
const Equalities & equalities = chain.second;
|
||||||
const Equalities & equalities = e.second;
|
|
||||||
|
|
||||||
/** Пропустить цепочку, если она слишком коротка или содержит данные разних типов.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!mustTransform(equalities))
|
if (!mustTransform(equalities))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/** Создать новое выражение IN.
|
auto in_expression = createInExpression(equalities);
|
||||||
*/
|
putInExpression(chain, in_expression);
|
||||||
|
|
||||||
auto in_expr = createInExpression(logical_or_with_lhs, equalities);
|
|
||||||
|
|
||||||
/** Вставить это выражение в запрос.
|
|
||||||
*/
|
|
||||||
|
|
||||||
ASTFunction * or_function = logical_or_with_lhs.or_function;
|
|
||||||
ASTExpressionList * expression_list = static_cast<ASTExpressionList *>(&*(or_function->children[0]));
|
|
||||||
auto & children = expression_list->children;
|
|
||||||
|
|
||||||
children.push_back(in_expr);
|
|
||||||
|
|
||||||
auto it = std::remove_if(children.begin(), children.end(), [&](const ASTPtr & node)
|
|
||||||
{
|
|
||||||
return std::binary_search(equalities.begin(), equalities.end(), node.get());
|
|
||||||
});
|
|
||||||
children.erase(it, children.end());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 3. Удалить узлы OR, которые имеют только один узел типа Function.
|
|
||||||
*/
|
|
||||||
fixBrokenOrExpressions();
|
fixBrokenOrExpressions();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,9 +143,7 @@ bool LogicalExpressionsOptimizer::mustTransform(const Equalities & equalities) c
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Создать новое выражение IN на основе цепочки OR.
|
LogicalExpressionsOptimizer::ASTFunctionPtr LogicalExpressionsOptimizer::createInExpression(const Equalities & equalities) const
|
||||||
/// Предполагается, что все нужны проверки уже сделаны в optimizeDisjunctiveEqualityChains.
|
|
||||||
LogicalExpressionsOptimizer::ASTFunctionPtr LogicalExpressionsOptimizer::createInExpression(const LogicalOrWithLeftHandSide & logical_or_with_lhs, const Equalities & equalities)
|
|
||||||
{
|
{
|
||||||
ASTPtr value_list = new ASTExpressionList;
|
ASTPtr value_list = new ASTExpressionList;
|
||||||
for (auto function : equalities)
|
for (auto function : equalities)
|
||||||
@ -202,6 +174,24 @@ LogicalExpressionsOptimizer::ASTFunctionPtr LogicalExpressionsOptimizer::createI
|
|||||||
return in_function;
|
return in_function;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LogicalExpressionsOptimizer::putInExpression(const DisjunctiveEqualityChain & chain, ASTFunctionPtr in_expression)
|
||||||
|
{
|
||||||
|
const LogicalOrWithLeftHandSide & logical_or_with_lhs = chain.first;
|
||||||
|
const Equalities & equalities = chain.second;
|
||||||
|
|
||||||
|
ASTFunction * or_function = logical_or_with_lhs.or_function;
|
||||||
|
ASTExpressionList * expression_list = static_cast<ASTExpressionList *>(&*(or_function->children[0]));
|
||||||
|
auto & children = expression_list->children;
|
||||||
|
|
||||||
|
children.push_back(in_expression);
|
||||||
|
|
||||||
|
auto it = std::remove_if(children.begin(), children.end(), [&](const ASTPtr & node)
|
||||||
|
{
|
||||||
|
return std::binary_search(equalities.begin(), equalities.end(), node.get());
|
||||||
|
});
|
||||||
|
children.erase(it, children.end());
|
||||||
|
}
|
||||||
|
|
||||||
void LogicalExpressionsOptimizer::fixBrokenOrExpressions()
|
void LogicalExpressionsOptimizer::fixBrokenOrExpressions()
|
||||||
{
|
{
|
||||||
for (const auto & e : disjunctive_equalities_map)
|
for (const auto & e : disjunctive_equalities_map)
|
||||||
@ -215,7 +205,7 @@ void LogicalExpressionsOptimizer::fixBrokenOrExpressions()
|
|||||||
|
|
||||||
if (children.size() == 1)
|
if (children.size() == 1)
|
||||||
{
|
{
|
||||||
std::vector<IAST *> & parents = parent_map[or_function];
|
IASTs & parents = parent_map[or_function];
|
||||||
for (auto & parent : parents)
|
for (auto & parent : parents)
|
||||||
{
|
{
|
||||||
parent->children.push_back(children[0]);
|
parent->children.push_back(children[0]);
|
||||||
|
Loading…
Reference in New Issue
Block a user