From e8d77fe8ec8d9e270e8311139406172ffe112caa Mon Sep 17 00:00:00 2001 From: Michael Kolupaev Date: Tue, 18 Jun 2013 09:43:35 +0000 Subject: [PATCH] Merge --- .../DB/Interpreters/ExpressionAnalyzer.h | 2 +- dbms/src/Interpreters/ExpressionActions.cpp | 57 +++++++++++++++++-- dbms/src/Interpreters/ExpressionAnalyzer.cpp | 30 +++++++--- dbms/src/Storages/StorageMergeTree.cpp | 2 +- 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/dbms/include/DB/Interpreters/ExpressionAnalyzer.h b/dbms/include/DB/Interpreters/ExpressionAnalyzer.h index a6639f6eb1b..ce4f4270087 100644 --- a/dbms/include/DB/Interpreters/ExpressionAnalyzer.h +++ b/dbms/include/DB/Interpreters/ExpressionAnalyzer.h @@ -223,7 +223,7 @@ private: * Для агрегатных функций - если нужно, сделать sign rewrite. */ void normalizeTree(); - void normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, bool in_sign_rewritten); + void normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias, bool in_sign_rewritten); /// Превратить перечисление значений или подзапрос в ASTSet. node - функция in или notIn. void makeSet(ASTFunction * node, const Block & sample_block); diff --git a/dbms/src/Interpreters/ExpressionActions.cpp b/dbms/src/Interpreters/ExpressionActions.cpp index a3687976367..a8961964724 100644 --- a/dbms/src/Interpreters/ExpressionActions.cpp +++ b/dbms/src/Interpreters/ExpressionActions.cpp @@ -439,22 +439,67 @@ void ExpressionActions::finalize(const Names & output_columns) if (final_columns.empty()) final_columns.insert(getAnyColumn(input_columns)); - NameSet used_columns = final_columns; + /// Какие столбцы нужны, чтобы выполнить действия от текущего до последнего. + NameSet needed_columns = final_columns; + /// Какие столбцы никто не будет трогать от текущего действия до последнего. + NameSet unmodified_columns; - for (size_t i = 0; i < actions.size(); ++i) + { + NamesAndTypesList sample_columns = sample_block.getColumnsList(); + for (NamesAndTypesList::iterator it = sample_columns.begin(); it != sample_columns.end(); ++it) + unmodified_columns.insert(it->first); + } + + /// Будем идти с конца и поодерживать множество нужных на данном этапе столбцов. + /// Будем выбрасывать ненужные действия, хотя обычно их нет по построению. + for (int i = static_cast(actions.size()) - 1; i >= 0; --i) { Action & action = actions[i]; + Names in = action.getNeededColumns(); + std::string out = action.result_name; - Names needed = action.getNeededColumns(); - used_columns.insert(needed.begin(), needed.end()); + if (action.type == Action::PROJECT) + { + needed_columns = NameSet(in.begin(), in.end()); + unmodified_columns.clear(); + } + else + { + if (!out.empty()) + { + /// Если результат не используется и нет побочных эффектов, выбросим действие. + if (!needed_columns.count(out) && + (action.type == Action::APPLY_FUNCTION + || action.type == Action::ADD_COLUMN + || action.type == Action::COPY_COLUMN)) + { + actions.erase(actions.begin() + i); + + if (unmodified_columns.count(out)) + { + sample_block.erase(out); + unmodified_columns.erase(out); + } + + continue; + } + + unmodified_columns.erase(out); + + needed_columns.erase(out); + } + + needed_columns.insert(in.begin(), in.end()); + } } + for (NamesAndTypesList::iterator it = input_columns.begin(); it != input_columns.end();) { NamesAndTypesList::iterator it0 = it; ++it; - if (!used_columns.count(it0->first)) + if (!needed_columns.count(it0->first)) { - if (sample_block.has(it0->first)) + if (unmodified_columns.count(it0->first)) sample_block.erase(it0->first); input_columns.erase(it0); } diff --git a/dbms/src/Interpreters/ExpressionAnalyzer.cpp b/dbms/src/Interpreters/ExpressionAnalyzer.cpp index dd85aa085a4..c988d133d6f 100644 --- a/dbms/src/Interpreters/ExpressionAnalyzer.cpp +++ b/dbms/src/Interpreters/ExpressionAnalyzer.cpp @@ -286,14 +286,15 @@ void ExpressionAnalyzer::normalizeTree() MapOfASTs tmp_map; if (needSignRewrite()) sign_column_name = getSignColumnName(); - normalizeTreeImpl(ast, tmp_map, tmp_set, false); + normalizeTreeImpl(ast, tmp_map, tmp_set, "", false); } /// finished_asts - уже обработанные вершины (и на что они заменены) /// current_asts - вершины в текущем стеке вызовов этого метода +/// current_alias - алиас, повешенный на предка ast (самого глебокого из предков с алиасами) /// in_sign_rewritten - находимся ли мы в поддереве, полученном в результате sign rewrite -void ExpressionAnalyzer::normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, bool in_sign_rewritten) +void ExpressionAnalyzer::normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_asts, SetOfASTs & current_asts, std::string current_alias, bool in_sign_rewritten) { if (finished_asts.count(ast)) { @@ -304,6 +305,11 @@ void ExpressionAnalyzer::normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_as ASTPtr initial_ast = ast; current_asts.insert(initial_ast); + std::string * my_alias = getAlias(ast); + std::string new_current_alias = current_alias; + if (my_alias && !my_alias->empty()) + new_current_alias = *my_alias; + /// rewrite правила, которые действуют при обходе сверху-вниз. if (!in_sign_rewritten && !sign_column_name.empty()) @@ -327,9 +333,9 @@ void ExpressionAnalyzer::normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_as { if (node->kind == ASTIdentifier::Column) { - /// Если это алиас + /// Если это алиас, но не родительский алиас (чтобы работали конструкции вроде "SELECT column+1 AS column"). Aliases::const_iterator jt = aliases.find(node->name); - if (jt != aliases.end()) + if (jt != aliases.end() && current_alias != node->name) { /// Заменим его на соответствующий узел дерева if (current_asts.count(jt->second)) @@ -365,19 +371,19 @@ void ExpressionAnalyzer::normalizeTreeImpl(ASTPtr & ast, MapOfASTs & finished_as for (ASTs::iterator it = ast->children.begin(); it != ast->children.end(); ++it) if (!dynamic_cast(&**it)) - normalizeTreeImpl(*it, finished_asts, current_asts, in_sign_rewritten); + normalizeTreeImpl(*it, finished_asts, current_asts, new_current_alias, in_sign_rewritten); - /// Действия, выполняемые снизу вверх. - /// Если секция WHERE или HAVING состоит из одного алиаса, ссылку нужно заменить не только в children, но и в where_expression и having_expression. if (ASTSelectQuery * select = dynamic_cast(&*ast)) { if (select->where_expression) - normalizeTreeImpl(select->where_expression, finished_asts, current_asts, in_sign_rewritten); + normalizeTreeImpl(select->where_expression, finished_asts, current_asts, new_current_alias, in_sign_rewritten); if (select->having_expression) - normalizeTreeImpl(select->having_expression, finished_asts, current_asts, in_sign_rewritten); + normalizeTreeImpl(select->having_expression, finished_asts, current_asts, new_current_alias, in_sign_rewritten); } + /// Действия, выполняемые снизу вверх. + if (ASTFunction * node = dynamic_cast(&*ast)) { if (node->name == "lambda") @@ -974,6 +980,12 @@ ExpressionActionsPtr ExpressionAnalyzer::getActions(bool project_result) { actions->add(ExpressionActions::Action::project(result_columns)); } + else + { + /// Не будем удалять исходные столбцы. + for (NamesAndTypesList::const_iterator it = columns.begin(); it != columns.end(); ++it) + result_names.push_back(it->first); + } actions->finalize(result_names); diff --git a/dbms/src/Storages/StorageMergeTree.cpp b/dbms/src/Storages/StorageMergeTree.cpp index b2f4a4280c2..15f14691f32 100644 --- a/dbms/src/Storages/StorageMergeTree.cpp +++ b/dbms/src/Storages/StorageMergeTree.cpp @@ -845,7 +845,7 @@ void StorageMergeTree::mergeParts(std::vector parts) full_path + parts[i]->name + '/', DEFAULT_BLOCK_SIZE, all_column_names, *this, parts[i], ranges, StoragePtr()), primary_expr)); } - /// Порядок потоков важен: при совпадении ключа элементы идет в порядке номера потока-источника. + /// Порядок потоков важен: при совпадении ключа элементы идут в порядке номера потока-источника. /// В слитом куске строки с одинаковым ключом должны идти в порядке возрастания идентификатора исходного куска, то есть (примерного) возрастания времени вставки. BlockInputStreamPtr merged_stream = sign_column.empty() ? new MergingSortedBlockInputStream(src_streams, sort_descr, DEFAULT_BLOCK_SIZE)