diff --git a/dbcon/mysql/CMakeLists.txt b/dbcon/mysql/CMakeLists.txt index 7bd6ed78b..cb176f371 100644 --- a/dbcon/mysql/CMakeLists.txt +++ b/dbcon/mysql/CMakeLists.txt @@ -40,6 +40,7 @@ set(libcalmysql_SRCS is_columnstore_files.cpp is_columnstore_extents.cpp columnstore_dataload.cpp + rulebased_optimizer.cpp ) set_source_files_properties(ha_mcs.cpp PROPERTIES COMPILE_FLAGS "-fno-implicit-templates") diff --git a/dbcon/mysql/ha_mcs_execplan.cpp b/dbcon/mysql/ha_mcs_execplan.cpp index 8685b01f1..e23cf47e6 100644 --- a/dbcon/mysql/ha_mcs_execplan.cpp +++ b/dbcon/mysql/ha_mcs_execplan.cpp @@ -78,6 +78,7 @@ using namespace cal_impl_if; #include "predicateoperator.h" #include "rewrites.h" #include "rowcolumn.h" +#include "rulebased_optimizer.h" #include "selectfilter.h" #include "simplecolumn_decimal.h" #include "simplecolumn_int.h" @@ -9206,162 +9207,6 @@ int cs_get_derived_plan(ha_columnstore_derived_handler* handler, THD* /*thd*/, S return 0; } -bool tableIsInUnion(const execplan::CalpontSystemCatalog::TableAliasName& table, CalpontSelectExecutionPlan& csep) -{ - return std::any_of(csep.unionVec().begin(), csep.unionVec().end(), - [&table](const auto& unionUnit) { - execplan::CalpontSelectExecutionPlan* unionUnitLocal = dynamic_cast(unionUnit.get()); - bool tableIsPresented = std::any_of(unionUnitLocal->tableList().begin(), unionUnitLocal->tableList().end(), - [&table](const auto& unionTable) { - return unionTable == table; - }); - return tableIsPresented; - }); -} - -bool matchParallelCES(CalpontSelectExecutionPlan& csep) -{ - auto tables = csep.tableList(); - // This is leaf and there are no other tables at this level. - // WIP filter out CSEPs with orderBy, groupBy, having - // WIP filter out CSEPs with nonSimpleColumns in projection - return tables.size() == 1 && !tables[0].isColumnstore() && !tableIsInUnion(tables[0], csep); -} - -CalpontSelectExecutionPlan::SelectList makeUnionFromTable(const size_t numberOfLegs, - CalpontSelectExecutionPlan& csep) -{ - CalpontSelectExecutionPlan::SelectList unionVec; - unionVec.reserve(numberOfLegs); - for (size_t i = 0; i < numberOfLegs; ++i) - { - unionVec.push_back(csep.cloneWORecursiveSelects()); - } - - return unionVec; -} - -// void applyParallelCES(CalpontSelectExecutionPlan& csep) -// { -// auto tables = csep.tableList(); -// for (auto it = tables.begin(); it != tables.end(); ++it) -// { -// if (!it->isColumnstore()) -// { -// size_t parallelFactor = 2; -// auto additionalUnionVec = makeUnionFromTable(parallelFactor, csep); -// csep.unionVec().insert(csep.unionVec().end(), additionalUnionVec.begin(), additionalUnionVec.end()); -// } -// } -// } - -void applyParallelCES(CalpontSelectExecutionPlan& csep) -{ - auto tables = csep.tableList(); - CalpontSelectExecutionPlan::TableList newTableList; - CalpontSelectExecutionPlan::SelectList newDerivedTableList; - static const std::string aliasPrefix = "$sub_"; - - // ATM Must be only 1 table - for (auto& table: tables) - { - if (!table.isColumnstore()) - { - auto derivedSCEP = csep.cloneWORecursiveSelects(); - // need to intro a level - std::string alias = aliasPrefix + table.schema + "_" + table.table; - - derivedSCEP->location(CalpontSelectExecutionPlan::FROM); - derivedSCEP->subType(CalpontSelectExecutionPlan::FROM_SUBS); - derivedSCEP->derivedTbAlias(alias); - - size_t parallelFactor = 2; - auto additionalUnionVec = makeUnionFromTable(parallelFactor, csep); - derivedSCEP->unionVec().insert(derivedSCEP->unionVec().end(), additionalUnionVec.begin(), additionalUnionVec.end()); - - // change parent to derived table columns - for (auto& rc : csep.returnedCols()) - { - auto* sc = dynamic_cast(rc.get()); - if (sc) - { - sc->tableName(""); - sc->schemaName(""); - sc->tableAlias(alias); - sc->colPosition(0); - } - } - - // WIP need to work with existing derived tables - newDerivedTableList.push_back(derivedSCEP); - // WIP - CalpontSystemCatalog::TableAliasName tn = make_aliasview("", "", alias, ""); - newTableList.push_back(tn); - } - } - - // SimpleColumn* sc = new SimpleColumn("test", "i1", "i", false, csep.sessionID()); - // string alias(table->alias.c_ptr()); - // sc->timeZone(csep.timeZone()); - // sc->partitions(getPartitions(table)); - // boost::shared_ptr spsc(sc); - - // csep.columnMap().insert({"`test`.`i1`.`i`", spsc}); - - csep.derivedTableList(newDerivedTableList); - csep.tableList(newTableList); -} - -struct Rule -{ - Rule(std::string&& name, bool (*matchRule)(CalpontSelectExecutionPlan&), - void (*applyRule)(CalpontSelectExecutionPlan&)) - : name(name), matchRule(matchRule), applyRule(applyRule) {}; - - std::string name; - bool (*matchRule)(CalpontSelectExecutionPlan&); - void (*applyRule)(CalpontSelectExecutionPlan&); - bool apply(CalpontSelectExecutionPlan& csep) - { - bool rewrite = false; - for (auto& table : csep.derivedTableList()) - { - auto& csepLocal = *dynamic_cast(table.get()); - if (matchRule(csepLocal)) - { - applyRule(csepLocal); - rewrite = true; - } - else - { - rewrite |= apply(csepLocal); - } - } - - for (auto& unionUnit : csep.unionVec()) - { - auto& unionUnitLocal = *dynamic_cast(unionUnit.get()); - - if (matchRule(unionUnitLocal)) - { - applyRule(unionUnitLocal); - rewrite = true; - } - else - { - rewrite |= apply(unionUnitLocal); - } - } - - if (matchRule(csep)) - { - applyRule(csep); - rewrite = true; - } - - return rewrite; - } -}; int cs_get_select_plan(ha_columnstore_select_handler* handler, THD* /*thd*/, SCSEP& csep, gp_walk_info& gwi, bool isSelectLexUnit) @@ -9393,15 +9238,7 @@ int cs_get_select_plan(ha_columnstore_select_handler* handler, THD* /*thd*/, SCS // Derived table projection and filter optimization. derivedTableOptimization(&gwi, csep); - // static const Rule rules[] = { - // {"paralliseCES", matchparalliseCES, applyParalliseCES}, - // /* add more here */ - // }; - - // auto matchParallelCES = [](CalpontSelectExecutionPlan&){return false;}; - // auto applyParallelCES = [](CalpontSelectExecutionPlan&){ return;}; - - Rule parallelCES{"parallelCES", matchParallelCES, applyParallelCES}; + optimizer::Rule parallelCES{"parallelCES", optimizer::matchParallelCES, optimizer::applyParallelCES}; { parallelCES.apply(*csep); diff --git a/dbcon/mysql/rulebased_optimizer.cpp b/dbcon/mysql/rulebased_optimizer.cpp new file mode 100644 index 000000000..f91777c7f --- /dev/null +++ b/dbcon/mysql/rulebased_optimizer.cpp @@ -0,0 +1,158 @@ +/* Copyright (C) 2025 MariaDB Corporation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include "execplan/calpontselectexecutionplan.h" +#include "execplan/simplecolumn.h" +#include "rulebased_optimizer.h" + +namespace optimizer { + +bool Rule::apply(execplan::CalpontSelectExecutionPlan& csep) +{ + bool rewrite = false; + for (auto& table : csep.derivedTableList()) + { + auto& csepLocal = *dynamic_cast(table.get()); + if (matchRule(csepLocal)) + { + applyRule(csepLocal); + rewrite = true; + } + else + { + rewrite |= apply(csepLocal); + } + } + + for (auto& unionUnit : csep.unionVec()) + { + auto& unionUnitLocal = *dynamic_cast(unionUnit.get()); + + if (matchRule(unionUnitLocal)) + { + applyRule(unionUnitLocal); + rewrite = true; + } + else + { + rewrite |= apply(unionUnitLocal); + } + } + + if (matchRule(csep)) + { + applyRule(csep); + rewrite = true; + } + + return rewrite; +} + + +bool tableIsInUnion(const execplan::CalpontSystemCatalog::TableAliasName& table, execplan::CalpontSelectExecutionPlan& csep) +{ + return std::any_of(csep.unionVec().begin(), csep.unionVec().end(), + [&table](const auto& unionUnit) { + execplan::CalpontSelectExecutionPlan* unionUnitLocal = dynamic_cast(unionUnit.get()); + bool tableIsPresented = std::any_of(unionUnitLocal->tableList().begin(), unionUnitLocal->tableList().end(), + [&table](const auto& unionTable) { + return unionTable == table; + }); + return tableIsPresented; + }); +} + +bool matchParallelCES(execplan::CalpontSelectExecutionPlan& csep) +{ + auto tables = csep.tableList(); + // This is leaf and there are no other tables at this level. + // WIP filter out CSEPs with orderBy, groupBy, having + // WIP filter out CSEPs with nonSimpleColumns in projection + return tables.size() == 1 && !tables[0].isColumnstore() && !tableIsInUnion(tables[0], csep); +} + +execplan::CalpontSelectExecutionPlan::SelectList makeUnionFromTable(const size_t numberOfLegs, + execplan::CalpontSelectExecutionPlan& csep) +{ + execplan::CalpontSelectExecutionPlan::SelectList unionVec; + unionVec.reserve(numberOfLegs); + for (size_t i = 0; i < numberOfLegs; ++i) + { + unionVec.push_back(csep.cloneWORecursiveSelects()); + } + + return unionVec; +} + +void applyParallelCES(execplan::CalpontSelectExecutionPlan& csep) +{ + auto tables = csep.tableList(); + execplan::CalpontSelectExecutionPlan::TableList newTableList; + execplan::CalpontSelectExecutionPlan::SelectList newDerivedTableList; + static const std::string aliasPrefix = "$sub_"; + + // ATM Must be only 1 table + for (auto& table: tables) + { + if (!table.isColumnstore()) + { + auto derivedSCEP = csep.cloneWORecursiveSelects(); + // need to intro a level + std::string alias = aliasPrefix + table.schema + "_" + table.table; + + derivedSCEP->location(execplan::CalpontSelectExecutionPlan::FROM); + derivedSCEP->subType(execplan::CalpontSelectExecutionPlan::FROM_SUBS); + derivedSCEP->derivedTbAlias(alias); + + size_t parallelFactor = 2; + auto additionalUnionVec = makeUnionFromTable(parallelFactor, csep); + derivedSCEP->unionVec().insert(derivedSCEP->unionVec().end(), additionalUnionVec.begin(), additionalUnionVec.end()); + + // change parent to derived table columns + for (auto& rc : csep.returnedCols()) + { + auto* sc = dynamic_cast(rc.get()); + if (sc) + { + sc->tableName(""); + sc->schemaName(""); + sc->tableAlias(alias); + sc->colPosition(0); + } + } + + // WIP need to work with existing derived tables + newDerivedTableList.push_back(derivedSCEP); + // WIP + execplan::CalpontSystemCatalog::TableAliasName tn = execplan::make_aliasview("", "", alias, ""); + newTableList.push_back(tn); + } + } + + // SimpleColumn* sc = new SimpleColumn("test", "i1", "i", false, csep.sessionID()); + // string alias(table->alias.c_ptr()); + // sc->timeZone(csep.timeZone()); + // sc->partitions(getPartitions(table)); + // boost::shared_ptr spsc(sc); + + // csep.columnMap().insert({"`test`.`i1`.`i`", spsc}); + + csep.derivedTableList(newDerivedTableList); + csep.tableList(newTableList); +} +} + diff --git a/dbcon/mysql/rulebased_optimizer.h b/dbcon/mysql/rulebased_optimizer.h new file mode 100644 index 000000000..3f0a3e10f --- /dev/null +++ b/dbcon/mysql/rulebased_optimizer.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2025 MariaDB Corporation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#pragma once + +#include +#include "execplan/calpontselectexecutionplan.h" + +namespace optimizer { + +struct Rule +{ + Rule(std::string&& name, bool (*matchRule)(execplan::CalpontSelectExecutionPlan&), + void (*applyRule)(execplan::CalpontSelectExecutionPlan&)) + : name(name), matchRule(matchRule), applyRule(applyRule) {}; + + std::string name; + bool (*matchRule)(execplan::CalpontSelectExecutionPlan&); + void (*applyRule)(execplan::CalpontSelectExecutionPlan&); + bool apply(execplan::CalpontSelectExecutionPlan& csep); +}; + +bool matchParallelCES(execplan::CalpontSelectExecutionPlan& csep); +void applyParallelCES(execplan::CalpontSelectExecutionPlan& csep); + +} \ No newline at end of file