コード例 #1
0
ファイル: QueryOptimizer.cs プロジェクト: ikvm/deveelsql
        private Expression CostAnalysisAndTransform(SelectExpression selectExpression)
        {
            Expression joinGraph = selectExpression.Join;
            Expression filterGraph = selectExpression.Filter;

            // The required final ordering of the select expression if necessary.
            // This is either the 'group by' ordering for an aggregate statement,
            // or 'order by' if it's not an aggregate.

            // Are we an aggregate?
            Expression[] resultOrderExps;
            bool[] resultOrderAsc;
            Expression sortComposite = null;
            bool aggregateExpression = false;

            if (selectExpression.IsAggregated) {
                // Yes, do we have group by clause?
                int groupbyCount = selectExpression.GroupBy.Count;
                resultOrderExps = new Expression[groupbyCount];
                resultOrderAsc = new bool[groupbyCount];
                for (int i = 0; i < groupbyCount; ++i) {
                    resultOrderExps[i] = selectExpression.GroupBy[i];
                    resultOrderAsc[i] = true;      // All group by ordering is ascending
                }
                // Note the aggregate,
                aggregateExpression = true;
            } else {
                // Not an aggregate statement, do we have a order by clause?
                int orderbyCount = selectExpression.OrderBy.Count;
                resultOrderExps = new Expression[orderbyCount];
                resultOrderAsc = new bool[orderbyCount];
                for (int i = 0; i < orderbyCount; ++i) {
                    resultOrderExps[i] = selectExpression.OrderBy[i].Expression;
                    resultOrderAsc[i] = selectExpression.OrderBy[i].IsAscending;
                }
            }
            // The sort composite
            if (resultOrderExps.Length > 0) {
                sortComposite = FunctionExpression.Composite(resultOrderExps, resultOrderAsc);
            }

            // Create a new query transform object
            QueryPlanner planner = new QueryPlanner(transaction);
            planner.SetFilterGraph(filterGraph);
            planner.SetJoinGraph(joinGraph);
            planner.SetResultSortComposite(sortComposite);
            Expression cheapResolution = planner.FindCheapResolution();

            // If this is an aggregate query, we apply the aggregate filter to the
            // query plan.
            if (aggregateExpression) {
                FilterExpression aggregateFilter =
                      new FilterExpression("aggregate", cheapResolution, sortComposite);
                cheapResolution = aggregateFilter;
                // Is there a having clause?
                Expression havingExp = selectExpression.Having;
                if (havingExp != null) {
                    FilterExpression havingFilter =
                        new FilterExpression("single_filter", cheapResolution, havingExp);
                    cheapResolution = havingFilter;
                }
                // Is there an order by clause?
                int orderbyCount = selectExpression.OrderBy.Count;
                if (orderbyCount > 0) {
                    Expression[] orderExps = new Expression[orderbyCount];
                    bool[] order_asc = new bool[orderbyCount];
                    for (int i = 0; i < orderbyCount; ++i) {
                        orderExps[i] = selectExpression.OrderBy[i].Expression;
                        order_asc[i] = selectExpression.OrderBy[i].IsAscending;
                    }

                    Expression aggrSortComposite = FunctionExpression.Composite(orderExps, order_asc);
                    FilterExpression sortFilter = new FilterExpression("sort", cheapResolution, aggrSortComposite);
                    cheapResolution = sortFilter;
                }
            }

            // cheap_resolution is the best plan found, now add decoration such as
            // filter terms, etc
            int outCount = selectExpression.Output.Count;
            FunctionExpression outFunction = new FunctionExpression("table_out");
            for (int i = 0; i < outCount; ++i) {
                outFunction.Parameters.Add(selectExpression.Output[i].Expression);
            }
            // Set the filter,
            Expression outFilter = new FilterExpression("expression_table", cheapResolution, outFunction);

            QueryCostModel costModel = new QueryCostModel(transaction);
            costModel.ClearGraph(outFilter);
            costModel.Cost(outFilter, Double.PositiveInfinity, new int[1]);

            return outFilter;
        }
コード例 #2
0
ファイル: QueryPlanner.cs プロジェクト: ikvm/deveelsql
        private Expression CreateRandomQueryPlan(IList<QueryPredicate> expressions, IList<TableName> sourceList, IList<Expression> sourceListExps, Expression joinGraph)
        {
            Expression static_expression = null;
            // For each input expression
            foreach (QueryPredicate expr in expressions) {
                // Find all static expressions (not dependant on terms in the current
                // query context) and make a single static expression to resolve it.
                int depend_on_count = expr.dependant_on.Count;
                // No dependants
                if (depend_on_count == 0) {
                    // Create the static expression if there is one,
                    static_expression = static_expression == null
                                            ? expr.expression
                                            : new FunctionExpression("@and_sql", new Expression[] {static_expression, expr.expression});
                }

                // Mark up index information
                MarkUpIndexCandidates(expr.expression);
                // Mark up fact information
                if (FactStatistics.CanBeFact(expr.expression)) {
                    Expression derefExp = QueryCostModel.DereferenceExpression(joinGraph, expr.expression);
                    if (derefExp != null) {
                        expr.expression.SetArgument("fact_id", FactStatistics.ToFactId(derefExp));
                    }
                }
            }

            // Create the sort function
            Expression sortFunction = null;
            if (sortComposite != null) {
                sortFunction = (Expression) sortComposite.Clone();
                // Mark up any index information on the composite
                MarkUpIndexCandidates(sortFunction);
            }

            // Create the cost model
            QueryCostModel costModel = new QueryCostModel(transaction);

            // The list of the best plans in the current iteration
            List<PlanState> plans1 = new List<PlanState>();

            int[] walkIteration = new int[1];

            long plan_seed = DateTime.Now.Ticks; // Arbitary starting seed value
            int cost_iterations = 0;

            // Randomly schedule
            for (int i = 0; i < 64; ++i) {
                // Produce a random plan
                IList<QueryPredicate> predOrder = ShufflePredicateOrder(expressions, 1.0d);
                Expression result = ProduceRandomPlan(plan_seed, predOrder, sourceListExps, joinGraph, sortFunction,
                                                      static_expression);
                // Cost it out
                costModel.ClearGraph(result);
                costModel.Cost(result, Double.PositiveInfinity, walkIteration);
                ++cost_iterations;
                double currentCostTime = result.CostTime;

                if (plans1.Count < 8 ||
                    plans1[plans1.Count - 1].cost > currentCostTime) {
                    // If it's a good plan, add it to the plan list
                    PlanState state1 = new PlanState(plan_seed, predOrder, currentCostTime);
                    int pos = plans1.BinarySearch(state1);
                    if (pos < 0) {
                        pos = -(pos + 1);
                    }
                    plans1.Insert(pos, state1);
                }

                // Ensure the list of good plans isn't more than 48
                if (plans1.Count > 48) {
                    plans1.RemoveAt(plans1.Count - 1);
                }

                // Increment the plan seed
                plan_seed += 500000;
            }

            // Now go through the list from the end to the start and shuffle the
            // predicates.  If a better plan is found we insert it back into the list.
            for (int i = plans1.Count - 1; i >= 0; --i) {
                int tryCount;
                int graphMessChance;
                if (i <= 2) {
                    tryCount = 32;
                    graphMessChance = 120;
                } else if (i <= 3) {
                    tryCount = 32;
                    graphMessChance = 120;
                } else if (i <= 5) {
                    tryCount = 24;
                    graphMessChance = 60;
                } else if (i <= 8) {
                    tryCount = 18;
                    graphMessChance = 30;
                } else if (i <= 16) {
                    tryCount = 18;
                    graphMessChance = 10;
                } else {
                    tryCount = 12;
                    graphMessChance = 1;
                }
                int worse_plans_count = 0;
                for (int n = 0; n < tryCount; ++n) {
                    PlanState curState = plans1[i];
                    plan_seed = curState.seed;
                    int bestI = System.Math.Min(plans1.Count - 1, 4);
                    double costToBeat = plans1[bestI].cost;
                    // Shuffle the predicate order of this plan
                    IList<QueryPredicate> predOrder = ShufflePredicateOrder(curState.predicate_order, 0.012d);
                    // 10% chance that we change the seed also,
                    if (i > 14 ||
                        new Random().Next(graphMessChance) == 0) {
                        plan_seed = plan_seed + 1;
                    }

                    Expression result = ProduceRandomPlan(plan_seed, predOrder, sourceListExps, joinGraph, sortFunction,
                                                          static_expression);
                    // Cost it out
                    costModel.ClearGraph(result);
                    costModel.Cost(result, costToBeat, walkIteration);
                    ++cost_iterations;
                    if (result.IsCostSet) {
                        double currentCostTime = result.CostTime;
                        // If it's a better plan, feed it back into the list
                        if (currentCostTime < curState.cost &&
                            currentCostTime < costToBeat) {
                            // If it's a good plan, add it to the plan list
                            PlanState state1 = new PlanState(plan_seed, predOrder, currentCostTime);
                            // NOTE; this doesn't add the entry to the list if there exists
                            //   an entry that's the same cost and seed.
                            int pos = plans1.BinarySearch(state1);
                            if (pos < 0) {
                                pos = -(pos + 1);
                                plans1.Insert(pos, state1);
                                ++i;
                            }
                        } else {
                            if (currentCostTime > costToBeat) {
                                ++worse_plans_count;
                            }
                        }
                    }
                }

                // Remove all plans down to i
                for (int n = plans1.Count - 1; n >= System.Math.Max(i, 8); --n) {
                    plans1.RemoveAt(n);
                }
            }

            // Make up the best plan from the seed,
            PlanState state = plans1[0];
            Expression bestExp = ProduceRandomPlan(state.seed, state.predicate_order, sourceListExps, joinGraph, sortFunction,
                                                   static_expression);

            // Make sure the cost information is correct for this graph before printing
            // it out
            costModel.ClearGraph(bestExp);
            costModel.Cost(bestExp, Double.PositiveInfinity, new int[1]);

            return bestExp;
        }