提交 cfc5b313 编写于 作者: A Alexey Milovidov

dbms: fixed 'force_index_by_date' setting [#METR-15484].

上级 048eed94
......@@ -124,7 +124,7 @@ struct Range
private:
static bool equals(const Field & lhs, const Field & rhs) { return apply_visitor(FieldVisitorAccurateEquals(), lhs, rhs); }
static bool less(const Field & lhs, const Field & rhs) { return apply_visitor(FieldVisitorAccurateLess(), lhs, rhs); }
public:
Field left; /// левая граница, если есть
Field right; /// правая граница, если есть
......@@ -132,17 +132,17 @@ public:
bool right_bounded; /// ограничен ли справа
bool left_included; /// включает левую границу, если есть
bool right_included; /// включает правую границу, если есть
/// Всё множество.
Range() : left(), right(), left_bounded(false), right_bounded(false), left_included(false), right_included(false) {}
/// Одна точка.
Range(const Field & point) : left(point), right(point), left_bounded(true), right_bounded(true), left_included(true), right_included(true) {}
/// Ограниченный с двух сторон диапазон.
Range(const Field & left_, bool left_included_, const Field & right_, bool right_included_)
: left(left_), right(right_), left_bounded(true), right_bounded(true), left_included(left_included_), right_included(right_included_) {}
static Range createRightBounded(const Field & right_point, bool right_included)
{
Range r;
......@@ -151,7 +151,7 @@ public:
r.right_included = right_included;
return r;
}
static Range createLeftBounded(const Field & left_point, bool left_included)
{
Range r;
......@@ -160,7 +160,7 @@ public:
r.left_included = left_included;
return r;
}
/// Установить левую границу.
void setLeft(const Field & point, bool included)
{
......@@ -168,7 +168,7 @@ public:
left_bounded = true;
left_included = included;
}
/// Установить правую границу.
void setRight(const Field & point, bool included)
{
......@@ -176,13 +176,13 @@ public:
right_bounded = true;
right_included = included;
}
/// x входит в range
bool contains(const Field & x) const
{
return !leftThan(x) && !rightThan(x);
}
/// x находится левее
bool rightThan(const Field & x) const
{
......@@ -190,7 +190,7 @@ public:
? !(less(left, x) || (left_included && equals(x, left)))
: false);
}
/// x находится правее
bool leftThan(const Field & x) const
{
......@@ -198,7 +198,7 @@ public:
? !(less(x, right) || (right_included && equals(x, right)))
: false);
}
bool intersectsRange(const Range & r) const
{
/// r левее меня.
......@@ -219,7 +219,7 @@ public:
return true;
}
bool containsRange(const Range & r) const
{
/// r начинается левее меня.
......@@ -242,49 +242,57 @@ public:
return true;
}
String toString() const
{
std::stringstream str;
if (!left_bounded)
str << "(-inf, ";
else
str << (left_included ? '[' : '(') << apply_visitor(FieldVisitorToString(), left) << ", ";
if (!right_bounded)
str << "+inf)";
else
str << apply_visitor(FieldVisitorToString(), right) << (right_included ? ']' : ')');
return str.str();
}
};
class ASTSet;
/** Условие на индекс.
*
* Состоит из условий на принадлежность ключа всевозможным диапазонам или множествам,
* а также логических связок AND/OR/NOT над этими условиями.
*
* Составляет reverse polish notation от этих условий
* и умеет вычислять (интерпретировать) её выполнимость над диапазонами ключа.
*/
class PKCondition
{
public:
/// Не учитывает секцию SAMPLE. all_columns - набор всех столбцов таблицы.
PKCondition(ASTPtr query, const Context & context, const NamesAndTypesList & all_columns, const SortDescription & sort_descr);
/// Выполнимо ли условие в диапазоне ключей.
/// left_pk и right_pk должны содержать все поля из sort_descr в соответствующем порядке.
bool mayBeTrueInRange(const Field * left_pk, const Field * right_pk);
/// Выполнимо ли условие в полубесконечном (не ограниченном справа) диапазоне ключей.
/// left_pk должен содержать все поля из sort_descr в соответствующем порядке.
bool mayBeTrueAfter(const Field * left_pk);
bool alwaysTrue()
{
return rpn.size() == 1 && rpn[0].function == RPNElement::FUNCTION_UNKNOWN;
}
/// Проверяет, что индекс не может быть использован.
bool alwaysUnknown();
/// Наложить дополнительное условие: значение в столбце column должно быть в диапазоне range.
/// Возвращает, есть ли такой столбец в первичном ключе.
bool addCondition(const String & column, const Range & range);
String toString();
private:
/// Выражение хранится в виде обратной польской строки (Reverse Polish Notation).
......@@ -303,37 +311,37 @@ private:
FUNCTION_AND,
FUNCTION_OR,
};
RPNElement() {}
RPNElement(Function function_) : function(function_) {}
RPNElement(Function function_, size_t key_column_) : function(function_), key_column(key_column_) {}
RPNElement(Function function_, size_t key_column_, const Range & range_)
: function(function_), range(range_), key_column(key_column_) {}
String toString();
Function function;
/// Для FUNCTION_IN_RANGE и FUNCTION_NOT_IN_RANGE.
Range range;
size_t key_column;
/// Для FUNCTION_IN_SET
ASTPtr in_function;
ASTSet * inFunctionToSet();
};
typedef std::vector<RPNElement> RPN;
typedef std::map<String, size_t> ColumnIndices;
bool mayBeTrueInRange(const Field * left_pk, const Field * right_pk, bool right_bounded);
void traverseAST(ASTPtr & node, Block & block_with_constants);
bool atomFromAST(ASTPtr & node, Block & block_with_constants, RPNElement & out);
bool operatorFromAST(ASTFunction * func, RPNElement & out);
RPN rpn;
SortDescription sort_descr;
ColumnIndices pk_columns;
};
......
......@@ -83,7 +83,7 @@ BlockInputStreams MergeTreeDataSelectExecutor::read(
PKCondition key_condition(query, context, data.getColumnsList(), data.getSortDescription());
PKCondition date_condition(query, context, data.getColumnsList(), SortDescription(1, SortColumnDescription(data.date_column_name, 1)));
if (settings.force_index_by_date && date_condition.alwaysTrue())
if (settings.force_index_by_date && date_condition.alwaysUnknown())
throw Exception("Index by date is not used and setting 'force_index_by_date' is set.", ErrorCodes::INDEX_NOT_USED);
/// Выберем куски, в которых могут быть данные, удовлетворяющие date_condition, и которые подходят под условие на _part.
......@@ -556,7 +556,7 @@ MarkRanges MergeTreeDataSelectExecutor::markRangesFromPkRange(
size_t marks_count = index.size() / key_size;
/// Если индекс не используется.
if (key_condition.alwaysTrue())
if (key_condition.alwaysUnknown())
{
res.push_back(MarkRange(0, marks_count));
}
......
......@@ -267,7 +267,7 @@ bool PKCondition::mayBeTrueInRange(const Field * left_pk, const Field * right_pk
RPNElement & element = rpn[i];
if (element.function == RPNElement::FUNCTION_UNKNOWN)
{
rpn_stack.push_back(BoolMask(true, true));
rpn_stack.emplace_back(true, true);
}
else if (element.function == RPNElement::FUNCTION_NOT_IN_RANGE || element.function == RPNElement::FUNCTION_IN_RANGE)
{
......@@ -275,7 +275,7 @@ bool PKCondition::mayBeTrueInRange(const Field * left_pk, const Field * right_pk
bool intersects = element.range.intersectsRange(key_range);
bool contains = element.range.containsRange(key_range);
rpn_stack.push_back(BoolMask(intersects, !contains));
rpn_stack.emplace_back(intersects, !contains);
if (element.function == RPNElement::FUNCTION_NOT_IN_RANGE)
rpn_stack.back() = !rpn_stack.back();
}
......@@ -294,7 +294,7 @@ bool PKCondition::mayBeTrueInRange(const Field * left_pk, const Field * right_pk
}
else
{
throw DB::Exception("Set for IN is not created yet!");
throw DB::Exception("Set for IN is not created yet!", ErrorCodes::LOGICAL_ERROR);
}
}
else if (element.function == RPNElement::FUNCTION_NOT)
......@@ -303,16 +303,16 @@ bool PKCondition::mayBeTrueInRange(const Field * left_pk, const Field * right_pk
}
else if (element.function == RPNElement::FUNCTION_AND)
{
BoolMask arg1 = rpn_stack.back();
auto arg1 = rpn_stack.back();
rpn_stack.pop_back();
BoolMask arg2 = rpn_stack.back();
auto arg2 = rpn_stack.back();
rpn_stack.back() = arg1 & arg2;
}
else if (element.function == RPNElement::FUNCTION_OR)
{
BoolMask arg1 = rpn_stack.back();
auto arg1 = rpn_stack.back();
rpn_stack.pop_back();
BoolMask arg2 = rpn_stack.back();
auto arg2 = rpn_stack.back();
rpn_stack.back() = arg1 | arg2;
}
else
......@@ -374,4 +374,50 @@ String PKCondition::RPNElement::toString()
return "ERROR";
}
}
bool PKCondition::alwaysUnknown()
{
std::vector<UInt8> rpn_stack;
for (size_t i = 0; i < rpn.size(); ++i)
{
RPNElement & element = rpn[i];
if (element.function == RPNElement::FUNCTION_UNKNOWN)
{
rpn_stack.push_back(true);
}
else if (element.function == RPNElement::FUNCTION_NOT_IN_RANGE
|| element.function == RPNElement::FUNCTION_IN_RANGE
|| element.function == RPNElement::FUNCTION_IN_SET
|| element.function == RPNElement::FUNCTION_NOT_IN_SET)
{
rpn_stack.push_back(false);
}
else if (element.function == RPNElement::FUNCTION_NOT)
{
}
else if (element.function == RPNElement::FUNCTION_AND)
{
auto arg1 = rpn_stack.back();
rpn_stack.pop_back();
auto arg2 = rpn_stack.back();
rpn_stack.back() = arg1 & arg2;
}
else if (element.function == RPNElement::FUNCTION_OR)
{
auto arg1 = rpn_stack.back();
rpn_stack.pop_back();
auto arg2 = rpn_stack.back();
rpn_stack.back() = arg1 | arg2;
}
else
throw Exception("Unexpected function type in PKCondition::RPNElement", ErrorCodes::LOGICAL_ERROR);
}
return rpn_stack[0];
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册