private List <QueryPlanNode> GetLeastCostPath(QueryPlanNode root) { QueryPlanNode cur = root; List <QueryPlanNode> result = new List <QueryPlanNode>(); result.Add(cur); while (cur != null) { QueryPlanNodeEdge cheapestEdge = cur.Edges.OrderBy(x => x.Cost).FirstOrDefault(); if (cheapestEdge != null) { cur = cheapestEdge.To; if (cur != null) { result.Add(cur); } } else { cur = null; } } return(result); }
//private PhysicalOperation FindIndexes(SelectionElement selectionElement) //{ // List<LeafCondition> leafs = GetLeafConditions(selectionElement.Condition); // foreach(LeafCondition leaf in leafs) // { // if (leaf.Column.Relation is TableDefinition tableDefinition) // { // Index index = tableDefinition.Indexes.FirstOrDefault(x => string.Equals(x.Column, leaf.Column.Name, StringComparison.OrdinalIgnoreCase)); // if (index != null) // { // ; // } // } // } // if (leafs.Count == 0) // { // // index seek / table scan // return GetFullTableScanOperation(selectionElement..) // } //} public PhysicalOperation GetPhysicalPlan(LogicalElement logicalTree) { List <LogicalElement> postorderLogicalTree = AppendPostOrder(new List <LogicalElement>(), logicalTree); QueryPlanNode root = new QueryPlanNode(null, null); List <QueryPlanNode> lastOptions = new List <QueryPlanNode> { root }; for (int i = 0; i < postorderLogicalTree.Count; i++) { LogicalElement element = postorderLogicalTree[i]; Dictionary <QueryPlanNode, int> options = GetOptions(element); ConnectEndNodesToNodes(lastOptions, options); lastOptions = options.Select(x => x.Key).ToList(); } List <QueryPlanNode> leastCostPath = GetLeastCostPath(root); PhysicalOperation physicalOperation = CreateFromPath(logicalTree, leastCostPath); return(physicalOperation); }
private static void Visit(ISelection selection, QueryPlanContext context) { if (selection.IsStreamable && selection.SelectionSet is not null) { QueryPlanContext streamContext = context.Branch(); VisitChildren(selection, streamContext); if (streamContext.Root is not null && !context.Streams.ContainsKey(selection.Id)) { context.Streams.Add(selection.Id, new(selection.Id, streamContext.Root)); } if (streamContext.Streams.Count > 0) { foreach (StreamPlanNode streamPlan in streamContext.Streams.Values) { if (!context.Streams.ContainsKey(selection.Id)) { context.Streams.Add(selection.Id, streamPlan); } } } } if (context.NodePath.Count == 0) { context.Root = new ResolverNode(selection); context.NodePath.Push(context.Root); } else { QueryPlanNode parent = context.NodePath.Peek(); if (selection.Strategy == SelectionExecutionStrategy.Serial) { if (parent is ResolverNode { Strategy : ExecutionStrategy.Serial } p) { p.Selections.Add(selection); } else if (context.SelectionPath.Count > 0 && context.NodePath.TryPeek(2, out QueryPlanNode? grandParent) && grandParent is ResolverNode { Strategy: ExecutionStrategy.Serial } gp&& gp.Selections.Contains(context.SelectionPath.PeekOrDefault() !)) { gp.Selections.Add(selection); }
public QueryPlanNode Provide(JObject jObject) { QueryTreeDataInternal queryTree = new QueryTreeDataInternal(); ProcessRtes(queryTree, jObject); QueryPlanNode result = null; var plan = jObject.SelectToken("..planTree"); if (plan != null) { result = LoadPlanNode(null, plan, queryTree); } return(result ?? new QueryPlanNode()); }
public static OperationNode Build(QueryPlanContext context) { var root = new SequenceNode { CancelOnError = true }; context.Root = root; context.NodePath.Push(root); foreach (ISelection mutation in context.Operation.GetRootSelectionSet().Selections) { context.SelectionPath.Push(mutation); var mutationStep = new ResolverNode( mutation, context.SelectionPath.PeekOrDefault(), GetStrategyFromSelection(mutation)); root.AddNode(mutationStep); QueryStrategy.VisitChildren(mutation, context); } context.NodePath.Pop(); QueryPlanNode optimized = QueryStrategy.Optimize(context.Root); var operationNode = new OperationNode(optimized); if (context.Deferred.Count > 0) { foreach (QueryPlanNode?deferred in QueryStrategy.BuildDeferred(context)) { operationNode.Deferred.Add(deferred); } } if (context.Streams.Count > 0) { operationNode.Streams.AddRange(context.Streams.Values); } return(operationNode); }
private void PublishIndexStatistics(QueryPlanNode plan) { switch (plan.ScanOperation) { case AnyIndexScanOperation indexScan: statementDataAccumulator.PublishNormalizedStatementIndexStatistics(new LogEntryStatementIndexStatisticsData() { DatabaseID = context.DatabaseID, ExecutionDate = context.Entry.Timestamp, IndexID = indexScan.IndexId, NormalizedStatementFingerprint = context.StatementData.NormalizedStatementFingerprint, TotalCost = plan.TotalCost }); break; } foreach (var item in plan.Plans) { PublishIndexStatistics(item); } }
public static OperationNode Build(QueryPlanContext context) { QueryPlanNode root = Build(context, context.Operation.GetRootSelectionSet()); var operationNode = new OperationNode(root); if (context.Deferred.Count > 0) { foreach (QueryPlanNode?deferred in BuildDeferred(context)) { operationNode.Deferred.Add(deferred); } } if (context.Streams.Count > 0) { operationNode.Streams.AddRange(context.Streams.Values); } return(operationNode); }
private QueryPlanNode LoadPlanNode(QueryPlanNode parent, JToken jObject, QueryTreeDataInternal queryTree) { if (jObject.ToString() != "<>") { var planNode = jObject.First.First; var operationName = ((JProperty)jObject.First).Name.ToUpper(); QueryPlanNode node = new QueryPlanNode(); node.StartupCost = planNode.SelectToken("startup_cost").Value <decimal>(); node.TotalCost = planNode.SelectToken("total_cost").Value <decimal>(); if (operationName.Contains("INDEX") && planNode.SelectToken("indexid") != null) { node.ScanOperation = new AnyIndexScanOperation() { IndexId = planNode.SelectToken("indexid").Value <uint>() }; } else if (operationName == "SEQSCAN" && planNode.SelectToken("scanrelid") != null) { var index = planNode.SelectToken("scanrelid").Value <int>(); var rte = queryTree.Rtes[index - 1]; if (rte.RelKind == RelKind.Relation) { node.ScanOperation = new RelationSequenceScanOperation() { RelationId = rte.RelId.Value }; } } var left = planNode.SelectToken("lefttree"); LoadPlanNode(node, left, queryTree); var right = planNode.SelectToken("righttree"); LoadPlanNode(node, right, queryTree); if (parent != null) { parent.Plans.Add(node); } return(node); } return(null); }
private static void CompareExecNodeSpec(int streamNum, QueryPlanNode expected, QueryPlanNode actual, IDictionary <TableLookupIndexReqKey, TableLookupIndexReqKey> indexNameMapping) { if (actual is QueryPlanNodeNoOp && expected == null) { } else if (actual is TableLookupNode && expected is TableLookupNode) { CompareTableLookup(streamNum, (TableLookupNode)expected, (TableLookupNode)actual, indexNameMapping); } else if (actual is TableOuterLookupNode && expected is TableOuterLookupNode) { CompareTableLookupOuter(streamNum, (TableOuterLookupNode)expected, (TableOuterLookupNode)actual, indexNameMapping); } else if (actual is LookupInstructionQueryPlanNode && expected is LookupInstructionQueryPlanNode) { CompareInstruction(streamNum, (LookupInstructionQueryPlanNode)expected, (LookupInstructionQueryPlanNode)actual, indexNameMapping); } else { Assert.Fail("Failed to compare plan node for stream " + streamNum + ", unhandled plan " + actual.GetType().Name); } }
private void ConnectEndNodesToNodes(QueryPlanNode node, Dictionary <QueryPlanNode, int> endNodes) { if (node.Edges.Count == 0) { foreach (KeyValuePair <QueryPlanNode, int> endNode in endNodes) { node.Edges.Add(new QueryPlanNodeEdge { From = node, To = endNode.Key, Cost = endNode.Value }); } } else { foreach (QueryPlanNode node1 in node.Edges.Select(x => x.To)) { ConnectEndNodesToNodes(node1, endNodes); } } }
private QueryPlanNode LoadPlanNode(QueryPlanNode parent, JToken jObject, ISet <string> allIndices) { QueryPlanNode node = new QueryPlanNode(); var nodeType = jObject.SelectToken("['Node Type']").Value <string>().ToUpper(); if (nodeType.Contains("INDEX") && jObject.SelectToken("['Index Name']") != null) { var indexName = jObject.SelectToken("['Index Name']").Value <string>(); node.ScanOperation = new AnyIndexScanOperation(); allIndices.Add(indexName); } node.StartupCost = jObject.SelectToken("['Startup Cost']").Value <decimal>(); node.TotalCost = jObject.SelectToken("['Total Cost']").Value <decimal>(); var plans = jObject.SelectToken("Plans"); if (plans != null) { foreach (var plan in plans.Children()) { node.Plans.Add(LoadPlanNode(node, plan, allIndices)); } } return(node); }
public OperationNode(QueryPlanNode operation) : base(ExecutionStrategy.Serial) { Operation = operation; AddNode(operation); }
public EmptyExplainResult() { PlanJson = ""; Plan = new QueryPlanNode(); }
public StreamPlanNode(int id, QueryPlanNode root) { Id = id; Root = root; }