1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-10-31 18:30:33 +03:00

feat(rbo,rules): rule matcher has been replaced with csep filter for a rule to relax rule filter predicates and endless loop has been fixed in pushdown predicates.

This commit is contained in:
drrtuy
2025-08-08 12:44:29 +00:00
committed by Leonid Fedorov
parent 67ac7f2f75
commit bbac8e70a1
7 changed files with 43 additions and 30 deletions

View File

@@ -44,6 +44,7 @@ set(libcalmysql_SRCS
columnstore_dataload.cpp
rulebased_optimizer.cpp
rbo_apply_parallel_ces.cpp
rbo_predicate_pushdown.cpp
)
set_source_files_properties(ha_mcs.cpp PROPERTIES COMPILE_FLAGS "-fno-implicit-templates")

View File

@@ -54,7 +54,7 @@ bool tableIsInUnion(const execplan::CalpontSystemCatalog::TableAliasName& table,
});
}
bool matchParallelCES(execplan::CalpontSelectExecutionPlan& csep)
bool parallelCESFilter(execplan::CalpontSelectExecutionPlan& csep)
{
auto tables = csep.tableList();
// This is leaf and there are no other tables at this level in neither UNION, nor derived table.
@@ -198,12 +198,13 @@ execplan::CalpontSelectExecutionPlan::SelectList makeUnionFromTable(
return unionVec;
}
void applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerContext& ctx)
bool applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerContext& ctx)
{
auto tables = csep.tableList();
execplan::CalpontSelectExecutionPlan::TableList newTableList;
execplan::CalpontSelectExecutionPlan::SelectList newDerivedTableList;
execplan::CalpontSelectExecutionPlan::ReturnedColumnList newReturnedColumns;
bool ruleHasBeenApplied = false;
// ATM Must be only 1 table
for (auto& table : tables)
@@ -246,6 +247,7 @@ void applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerCon
// Remove the filters as they were pushed down to union units
// This is inappropriate for EXISTS filter and join conditions
derivedSCEP->filters(nullptr);
ruleHasBeenApplied = true;
}
}
// Remove the filters if necessary using csep.filters(nullptr) as they were pushed down to union units
@@ -255,6 +257,7 @@ void applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerCon
// Replace table list with new table list populated with union units
csep.tableList(newTableList);
csep.returnedCols(newReturnedColumns);
return ruleHasBeenApplied;
}
} // namespace optimizer

View File

@@ -25,6 +25,6 @@
#include "rulebased_optimizer.h"
namespace optimizer {
bool matchParallelCES(execplan::CalpontSelectExecutionPlan& csep);
void applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx);
bool parallelCESFilter(execplan::CalpontSelectExecutionPlan& csep);
bool applyParallelCES(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx);
}

View File

@@ -29,13 +29,16 @@
namespace optimizer
{
bool matchPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep)
using DerivedToFiltersMap = std::map<std::string, execplan::ParseTree*>;
bool predicatePushdownFilter(execplan::CalpontSelectExecutionPlan& csep)
{
// The original rule match contains questionable decision to filter out
// queries that contains any UNION UNIT with only derived tables.
// See ha_from_sub.cpp before MCS 23.10.7 for more details and @bug6156.
// All tables are derived thus nothing to optimize.
return !csep.tableList().empty();
return !
csep.tableList().empty();
}
@@ -73,7 +76,7 @@ void setDerivedTable(execplan::ParseTree* n)
}
}
execplan::ParseTree* setDerivedFilter(cal_impl_if::gp_walk_info* gwip, execplan::ParseTree*& n, map<string, execplan::ParseTree*>& filterMap,
execplan::ParseTree* setDerivedFilter(cal_impl_if::gp_walk_info* gwip, execplan::ParseTree*& n, DerivedToFiltersMap& filterMap,
const execplan::CalpontSelectExecutionPlan::SelectList& derivedTbList)
{
if (!(n->derivedTable().empty()))
@@ -99,11 +102,11 @@ execplan::ParseTree* setDerivedFilter(cal_impl_if::gp_walk_info* gwip, execplan:
// 2. push the filter to the derived table filter stack, or 'and' with
// the filters in the stack
map<string, execplan::ParseTree*>::iterator mapIter = filterMap.find(n->derivedTable());
auto mapIter = filterMap.find(n->derivedTable());
if (mapIter == filterMap.end())
{
filterMap.insert(pair<string, execplan::ParseTree*>(n->derivedTable(), n));
filterMap.insert({n->derivedTable(), n});
}
else
{
@@ -141,7 +144,7 @@ execplan::ParseTree* setDerivedFilter(cal_impl_if::gp_walk_info* gwip, execplan:
return n;
}
void applyPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerContext& ctx)
bool applyPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep, RBOptimizerContext& ctx)
{
/*
* @bug5635. Move filters that only belongs to a derived table to inside the derived table.
@@ -158,8 +161,9 @@ void applyPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep, RBOptimi
* stacked filter needs to be reset (not null)
*/
execplan::ParseTree* pt = csep.filters();
map<string, execplan::ParseTree*> derivedTbFilterMap;
DerivedToFiltersMap derivedTbFilterMap;
auto& derivedTbList = csep.derivedTableList();
bool hasBeenApplied = false;
if (pt)
{
@@ -171,13 +175,11 @@ void applyPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep, RBOptimi
// AND the filters of individual stack to the derived table filter tree
// @todo union filters.
// @todo outer join complication
map<string, execplan::ParseTree*>::iterator mapIt;
for (uint i = 0; i < derivedTbList.size(); i++)
{
execplan::CalpontSelectExecutionPlan* plan = dynamic_cast<execplan::CalpontSelectExecutionPlan*>(derivedTbList[i].get());
execplan::CalpontSelectExecutionPlan::ReturnedColumnList derivedColList = plan->returnedCols();
mapIt = derivedTbFilterMap.find(plan->derivedTbAlias());
auto mapIt = derivedTbFilterMap.find(plan->derivedTbAlias());
if (mapIt != derivedTbFilterMap.end())
{
@@ -225,12 +227,17 @@ void applyPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep, RBOptimi
unionPlan->filters(mainFilterForUnion);
}
}
hasBeenApplied = true;
}
}
// clean derivedTbFilterMap because all the filters are copied
for (mapIt = derivedTbFilterMap.begin(); mapIt != derivedTbFilterMap.end(); ++mapIt)
delete (*mapIt).second;
for (auto mapIt = derivedTbFilterMap.begin(); mapIt != derivedTbFilterMap.end(); ++mapIt)
{
delete (*mapIt).second;
}
return hasBeenApplied;
}
} // namespace optimizer

View File

@@ -25,6 +25,6 @@
#include "rulebased_optimizer.h"
namespace optimizer {
bool matchPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep);
void applyPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx);
bool predicatePushdownFilter(execplan::CalpontSelectExecutionPlan& csep);
bool applyPredicatePushdown(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimizerContext& ctx);
}

View File

@@ -31,6 +31,7 @@
#include "predicateoperator.h"
#include "simplefilter.h"
#include "rbo_apply_parallel_ces.h"
#include "rbo_predicate_pushdown.h"
namespace optimizer
{
@@ -54,12 +55,12 @@ bool optimizeCSEP(execplan::CalpontSelectExecutionPlan& root, optimizer::RBOptim
if (get_unstable_optimizer(&ctx.thd))
{
optimizer::Rule parallelCES{"parallelCES", optimizer::matchParallelCES, optimizer::applyParallelCES};
optimizer::Rule parallelCES{"parallelCES", optimizer::parallelCESFilter, optimizer::applyParallelCES};
rules.push_back(parallelCES);
}
optimizer::Rule predicatePushdown{"predicatePushdown", optimizer::matchParallelCES,
optimizer::applyParallelCES};
optimizer::Rule predicatePushdown{"predicatePushdown", optimizer::predicatePushdownFilter,
optimizer::applyPredicatePushdown};
rules.push_back(predicatePushdown);
return optimizeCSEPWithRules(root, rules, ctx);
@@ -114,7 +115,7 @@ bool Rule::walk(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimiz
}
// Walk nested subselect in filters, e.g. SEMI-JOIN
for (auto& subselect : csep.subSelectList())
for (auto& subselect : current->subSelectList())
{
auto* subselectPtr = dynamic_cast<execplan::CalpontSelectExecutionPlan*>(subselect.get());
if (subselectPtr)
@@ -125,11 +126,10 @@ bool Rule::walk(execplan::CalpontSelectExecutionPlan& csep, optimizer::RBOptimiz
// TODO add walking nested subselect in projection. See CSEP::fSelectSubList
if (matchRule(*current))
if (mayApply(*current))
{
applyRule(*current, ctx);
rewrite = applyRule(*current, ctx);
++ctx.uniqueId;
rewrite = true;
}
}

View File

@@ -42,14 +42,16 @@ public:
struct Rule
{
using RuleMatcher = bool (*)(execplan::CalpontSelectExecutionPlan&);
using RuleApplier = void (*)(execplan::CalpontSelectExecutionPlan&, RBOptimizerContext&);
// returns true if rule may be applied
using RuleApplierFilter = bool (*)(execplan::CalpontSelectExecutionPlan&);
// returns true if rule was applied
using RuleApplier = bool (*)(execplan::CalpontSelectExecutionPlan&, RBOptimizerContext&);
Rule(std::string&& name, RuleMatcher matchRule, RuleApplier applyRule)
: name(name), matchRule(matchRule), applyRule(applyRule) {};
Rule(std::string&& name, RuleApplierFilter mayApply, RuleApplier applyRule)
: name(name), mayApply(mayApply), applyRule(applyRule) {};
std::string name;
RuleMatcher matchRule;
RuleApplierFilter mayApply;
RuleApplier applyRule;
// TODO Wrap CSEP into Nodes to be able to navigate up and down the tree and remove this flag
bool applyOnlyOnce = true;