void SubExpressionTap::Optimize(Block *block){ blocks.push(block); SubExpressionBlock *exprList = block->GetExprBlock(); const int size = block->body.size(); for(int i = 0; i < size; i++){ Node *expr = block->body[i + temp_counter]; if(expr->isCycle()) continue; if(Block* b = dynamic_cast<Block*>(expr)){ Optimize(b); continue; } if(FuncCallNode *cNode = dynamic_cast<FuncCallNode*>(expr)){ for(Node *arg : cNode->args) GetArgs(*exprList, arg); continue; } if(IfStatement *$if = dynamic_cast<IfStatement*>(expr)){ Optimize(dynamic_cast<Block*>($if->if_branch)); if($if->else_branch) Optimize(dynamic_cast<Block*>($if->else_branch)); continue; } if(ReturnStatement *retNode = dynamic_cast<ReturnStatement*>(expr)) expr = retNode->value; if(!expr->isExpression()) continue; Node *t = OptimizeExpression(expr); if(t != expr){ block->body[i + temp_counter] = t; } } ReplaceFirstOccur(); blocks.pop(); }
Node* SubExpressionTap::OptimizeExpression(Node *node){ Block *block = blocks.top(); SubExpressionBlock *expBlock = block->exprBlock; vector<Node*> *opList = expBlock->expressions[node->value()]; if(opList) for(Node *expr : *opList){ if(expr == node){ if(expr->commonNode){ if(*expr->commonNode == expr){ CreateNewIdent(expr->commonNode); return expr->commonNode->replaced; } return expr; } } } if(BinaryOpNode *bNode = dynamic_cast<BinaryOpNode*>(node)){ Node *l_opt = OptimizeExpression(bNode->left), *r_opt = OptimizeExpression(bNode->right); if(bNode->left != l_opt) bNode->left = l_opt; if(bNode->right != r_opt) bNode->right = r_opt; } else if(UnaryOpNode *uNode = dynamic_cast<UnaryOpNode*>(node)){ bool opt = false; for(Node *expr : *opList){ if(uNode->operand == expr){ opt = true; if(uNode->operand->commonNode) CreateNewIdent(uNode->operand->commonNode); Node *optNode = OptimizeExpression(uNode->operand); if(optNode != uNode->operand){ delete uNode->operand; uNode->operand = optNode; } break; } } if(!opt) OptimizeExpression(uNode->operand); } return node; }
void Optimizer::OptimizeGroup(GroupID id, PropertySet requirements) { LOG_TRACE("Optimizing group %d", id); Group *group = memo.GetGroupByID(id); const std::vector<std::shared_ptr<GroupExpression>> exprs = group->GetExpressions(); for (size_t i = 0; i < exprs.size(); ++i) { OptimizeExpression(exprs[i], requirements); } }
void Optimizer::OptimizeExpression(std::shared_ptr<GroupExpression> gexpr, PropertySet requirements) { LOG_TRACE("Optimizing expression of group %d with op %s", gexpr->GetGroupID(), gexpr->Op().name().c_str()); // Helper function for costing follow up expressions auto CostCandidate = [this](std::shared_ptr<GroupExpression> candidate, PropertySet requirements) { // Cost the expression this->CostExpression(candidate); // Only include cost if it meets the property requirements if (requirements.IsSubset(candidate->Op().ProvidedOutputProperties())) { // Add to group as potential best cost Group *group = this->memo.GetGroupByID(candidate->GetGroupID()); LOG_TRACE("Adding expression cost on group %d with op %s", candidate->GetGroupID(), candidate->Op().name().c_str()); group->SetExpressionCost(candidate, candidate->GetCost(), requirements); } }; // Cost the root expression if (gexpr->Op().IsPhysical()) { CostCandidate(gexpr, requirements); // Transformation rules shouldn't match on physical operators so don't apply // rules } else { // Apply transformations and cost those which match the requirements for (const std::unique_ptr<Rule> &rule : rules) { // Apply all rules to operator which match. We apply all rules to one // operator before moving on to the next operator in the group because // then we avoid missing the application of a rule e.g. an application // of some rule creates a match for a previously applied rule, but it is // missed because the prev rule was already checked std::vector<std::shared_ptr<GroupExpression>> candidates = TransformExpression(gexpr, *(rule.get())); for (std::shared_ptr<GroupExpression> candidate : candidates) { // If logical... if (candidate->Op().IsLogical()) { // Optimize the expression OptimizeExpression(candidate, requirements); } if (candidate->Op().IsPhysical()) { CostCandidate(candidate, requirements); } } } } }
std::shared_ptr<planner::AbstractPlan> Optimizer::GeneratePlan( std::shared_ptr<Select> select_tree) { // Generate initial operator tree from query tree std::shared_ptr<GroupExpression> gexpr = InsertQueryTree(select_tree); GroupID root_id = gexpr->GetGroupID(); // Get the physical properties the final plan must output PropertySet properties = GetQueryTreeRequiredProperties(select_tree); // Find least cost plan for root group OptimizeExpression(gexpr, properties); std::shared_ptr<OpExpression> best_plan = ChooseBestPlan(root_id, properties); if (best_plan == nullptr) return nullptr; planner::AbstractPlan *top_plan = OptimizerPlanToPlannerPlan(best_plan); std::shared_ptr<planner::AbstractPlan> final_plan(top_plan); return final_plan; }