public void TestCreateStreamPlan() { QueryPlanIndexForge[] indexes = QueryPlanIndexBuilder.BuildIndexSpec(queryGraph, typesPerStream, new string[queryGraph.NumStreams][][]); for (int i = 0; i < indexes.Length; i++) { log.Debug(".testCreateStreamPlan index " + i + " = " + indexes[i]); } QueryPlanNodeForge plan = NStreamQueryPlanBuilder.CreateStreamPlan(0, new int[] { 2, 4, 3, 1 }, queryGraph, indexes, typesPerStream, new bool[5], null, new TableMetaData[queryGraph.NumStreams], new StreamJoinAnalysisResultCompileTime(5)); log.Debug(".testCreateStreamPlan plan=" + plan); Assert.IsTrue(plan is NestedIterationNodeForge); NestedIterationNodeForge nested = (NestedIterationNodeForge)plan; TableLookupNodeForge tableLookupSpec = (TableLookupNodeForge)nested.ChildNodes[0]; // Check lookup strategy for first lookup IndexedTableLookupPlanHashedOnlyForge lookupStrategySpec = (IndexedTableLookupPlanHashedOnlyForge)tableLookupSpec.LookupStrategySpec; Assert.AreEqual("P01", ((ExprIdentNode)(lookupStrategySpec.HashKeys[0]).KeyExpr).ResolvedPropertyName); Assert.AreEqual(0, lookupStrategySpec.LookupStream); Assert.AreEqual(2, lookupStrategySpec.IndexedStream); Assert.IsNotNull(lookupStrategySpec.IndexNum); // Check lookup strategy for last lookup tableLookupSpec = (TableLookupNodeForge)nested.ChildNodes[3]; FullTableScanLookupPlanForge unkeyedSpecScan = (FullTableScanLookupPlanForge)tableLookupSpec.LookupStrategySpec; Assert.AreEqual(1, unkeyedSpecScan.IndexedStream); Assert.IsNotNull(unkeyedSpecScan.IndexNum); }
private static void CompareExecNodeSpec( int streamNum, QueryPlanNodeForge expected, QueryPlanNodeForge actual, IDictionary<TableLookupIndexReqKey, TableLookupIndexReqKey> indexNameMapping) { if (actual is QueryPlanNodeNoOpForge && expected == null) { } else if (actual is TableLookupNodeForge && expected is TableLookupNodeForge) { CompareTableLookup( streamNum, (TableLookupNodeForge) expected, (TableLookupNodeForge) actual, indexNameMapping); } else if (actual is TableOuterLookupNodeForge && expected is TableOuterLookupNodeForge) { CompareTableLookupOuter( streamNum, (TableOuterLookupNodeForge) expected, (TableOuterLookupNodeForge) actual, indexNameMapping); } else if (actual is LookupInstructionQueryPlanNodeForge && expected is LookupInstructionQueryPlanNodeForge) { CompareInstruction( streamNum, (LookupInstructionQueryPlanNodeForge) expected, (LookupInstructionQueryPlanNodeForge) actual, indexNameMapping); } else { Assert.Fail( "Failed to compare plan node for stream " + streamNum + ", unhandled plan " + actual.GetType().Name); } }
public static QueryPlanForgeDesc Build( QueryGraphForge queryGraph, EventType[] typesPerStream, HistoricalViewableDesc historicalViewableDesc, DependencyGraph dependencyGraph, HistoricalStreamIndexListForge[] historicalStreamIndexLists, bool hasForceNestedIter, string[][][] indexedStreamsUniqueProps, TableMetaData[] tablesPerStream, StreamJoinAnalysisResultCompileTime streamJoinAnalysisResult, StatementRawInfo raw, SerdeCompileTimeResolver serdeResolver) { if (Log.IsDebugEnabled) { Log.Debug(".build filterQueryGraph=" + queryGraph); } var numStreams = queryGraph.NumStreams; var additionalForgeables = new List<StmtClassForgeableFactory>(); var indexSpecs = QueryPlanIndexBuilder.BuildIndexSpec( queryGraph, typesPerStream, indexedStreamsUniqueProps); if (Log.IsDebugEnabled) { Log.Debug(".build Index build completed, indexes=" + QueryPlanIndexForge.Print(indexSpecs)); } // any historical streams don't get indexes, the lookup strategy accounts for cached indexes if (historicalViewableDesc.IsHistorical) { for (var i = 0; i < historicalViewableDesc.Historical.Length; i++) { if (historicalViewableDesc.Historical[i]) { indexSpecs[i] = null; } } } var planNodeSpecs = new QueryPlanNodeForge[numStreams]; var worstDepth = int.MaxValue; for (var streamNo = 0; streamNo < numStreams; streamNo++) { // no plan for historical streams that are dependent upon other streams if (historicalViewableDesc.Historical[streamNo] && dependencyGraph.HasDependency(streamNo)) { planNodeSpecs[streamNo] = new QueryPlanNodeNoOpForge(); continue; } var bestChainResult = ComputeBestPath(streamNo, queryGraph, dependencyGraph); var bestChain = bestChainResult.Chain; if (Log.IsDebugEnabled) { Log.Debug(".build For stream " + streamNo + " bestChain=" + bestChain.RenderAny()); } if (bestChainResult.Depth < worstDepth) { worstDepth = bestChainResult.Depth; } var planDesc = CreateStreamPlan( streamNo, bestChain, queryGraph, indexSpecs, typesPerStream, historicalViewableDesc.Historical, historicalStreamIndexLists, tablesPerStream, streamJoinAnalysisResult, raw, serdeResolver); planNodeSpecs[streamNo] = planDesc.Forge; additionalForgeables.AddAll(planDesc.AdditionalForgeables); if (Log.IsDebugEnabled) { Log.Debug(".build spec=" + planNodeSpecs[streamNo]); } } // We use the merge/nested (outer) join algorithm instead. if (worstDepth < numStreams - 1 && !hasForceNestedIter) { return null; } // build historical index and lookup strategies for (var i = 0; i < numStreams; i++) { var plan = planNodeSpecs[i]; QueryPlanNodeForgeVisitor visitor = new ProxyQueryPlanNodeForgeVisitor { ProcVisit = node => { if (node is HistoricalDataPlanNodeForge) { var historical = (HistoricalDataPlanNodeForge) node; JoinSetComposerPrototypeHistoricalDesc desc = historicalStreamIndexLists[historical.StreamNum].GetStrategy( historical.LookupStreamNum, raw, serdeResolver); historical.PollResultIndexingStrategy = desc.IndexingForge; historical.HistoricalIndexLookupStrategy = desc.LookupForge; additionalForgeables.AddAll(desc.AdditionalForgeables); } } }; plan.Accept(visitor); } var forge = new QueryPlanForge(indexSpecs, planNodeSpecs); return new QueryPlanForgeDesc(forge, additionalForgeables); }
/// <summary> /// Build query plan. /// </summary> /// <param name="queryGraph">navigability info</param> /// <param name="optionalOuterJoinType">outer join type, null if not an outer join</param> /// <param name="typesPerStream">event types for each stream</param> /// <param name="streamJoinAnalysisResult">stream join analysis</param> /// <returns>query plan</returns> public static QueryPlanForgeDesc Build( EventType[] typesPerStream, QueryGraphForge queryGraph, OuterJoinType? optionalOuterJoinType, StreamJoinAnalysisResultCompileTime streamJoinAnalysisResult, StatementRawInfo raw) { var uniqueIndexProps = streamJoinAnalysisResult.UniqueKeys; var tablesPerStream = streamJoinAnalysisResult.TablesPerStream; var additionalForgeable = new List<StmtClassForgeableFactory>(); var indexSpecs = QueryPlanIndexBuilder.BuildIndexSpec( queryGraph, typesPerStream, uniqueIndexProps); var execNodeSpecs = new QueryPlanNodeForge[2]; var lookupPlans = new TableLookupPlanForge[2]; // plan lookup from 1 to zero TableLookupPlanDesc plan1to0 = NStreamQueryPlanBuilder.CreateLookupPlan( queryGraph, 1, 0, streamJoinAnalysisResult.IsVirtualDW(0), indexSpecs[0], typesPerStream, tablesPerStream[0], raw, SerdeCompileTimeResolverNonHA.INSTANCE); lookupPlans[1] = plan1to0.Forge; additionalForgeable.AddAll(plan1to0.AdditionalForgeables); // plan lookup from zero to 1 TableLookupPlanDesc plan0to1 = NStreamQueryPlanBuilder.CreateLookupPlan( queryGraph, 0, 1, streamJoinAnalysisResult.IsVirtualDW(1), indexSpecs[1], typesPerStream, tablesPerStream[1], raw, SerdeCompileTimeResolverNonHA.INSTANCE); lookupPlans[0] = plan0to1.Forge; additionalForgeable.AddAll(plan0to1.AdditionalForgeables); execNodeSpecs[0] = new TableLookupNodeForge(lookupPlans[0]); execNodeSpecs[1] = new TableLookupNodeForge(lookupPlans[1]); if (optionalOuterJoinType != null) { if ((optionalOuterJoinType.Equals(OuterJoinType.LEFT)) || (optionalOuterJoinType.Equals(OuterJoinType.FULL))) { execNodeSpecs[0] = new TableOuterLookupNodeForge(lookupPlans[0]); } if ((optionalOuterJoinType.Equals(OuterJoinType.RIGHT)) || (optionalOuterJoinType.Equals(OuterJoinType.FULL))) { execNodeSpecs[1] = new TableOuterLookupNodeForge(lookupPlans[1]); } } var forge = new QueryPlanForge(indexSpecs, execNodeSpecs); return new QueryPlanForgeDesc(forge, additionalForgeable); }
public void Visit(QueryPlanNodeForge node) { ProcVisit?.Invoke(node); }
internal static QueryPlanForgeDesc Build( QueryGraphForge queryGraph, OuterJoinDesc[] outerJoinDescList, string[] streamNames, EventType[] typesPerStream, HistoricalViewableDesc historicalViewableDesc, DependencyGraph dependencyGraph, HistoricalStreamIndexListForge[] historicalStreamIndexLists, string[][][] indexedStreamsUniqueProps, TableMetaData[] tablesPerStream, StreamJoinAnalysisResultCompileTime streamJoinAnalysisResult, StatementRawInfo statementRawInfo, StatementCompileTimeServices services) { if (Log.IsDebugEnabled) { Log.Debug(".build filterQueryGraph=" + queryGraph); } var numStreams = queryGraph.NumStreams; var planNodeSpecs = new QueryPlanNodeForge[numStreams]; var additionalForgeables = new List<StmtClassForgeableFactory>(); // Build index specifications var indexSpecs = QueryPlanIndexBuilder.BuildIndexSpec( queryGraph, typesPerStream, indexedStreamsUniqueProps); // any historical streams don't get indexes, the lookup strategy accounts for cached indexes if (historicalViewableDesc.IsHistorical) { for (var i = 0; i < historicalViewableDesc.Historical.Length; i++) { if (historicalViewableDesc.Historical[i]) { indexSpecs[i] = null; } } } // Build graph of the outer join to inner table relationships. // Build a map of inner joins. OuterInnerDirectionalGraph outerInnerGraph; InnerJoinGraph innerJoinGraph; if (outerJoinDescList.Length > 0) { outerInnerGraph = GraphOuterJoins(numStreams, outerJoinDescList); innerJoinGraph = InnerJoinGraph.GraphInnerJoins(numStreams, outerJoinDescList); } else { // all inner joins - thereby no (or empty) directional graph outerInnerGraph = new OuterInnerDirectionalGraph(numStreams); innerJoinGraph = new InnerJoinGraph(numStreams, true); } if (Log.IsDebugEnabled) { Log.Debug(".build directional graph=" + outerInnerGraph.Print()); } // For each stream determine the query plan for (var streamNo = 0; streamNo < numStreams; streamNo++) { // no plan for historical streams that are dependent upon other streams if (historicalViewableDesc.Historical[streamNo] && dependencyGraph.HasDependency(streamNo)) { planNodeSpecs[streamNo] = new QueryPlanNodeNoOpForge(); continue; } QueryPlanNodeForgeDesc desc = BuildPlanNode( numStreams, streamNo, streamNames, queryGraph, outerInnerGraph, outerJoinDescList, innerJoinGraph, indexSpecs, typesPerStream, historicalViewableDesc.Historical, dependencyGraph, historicalStreamIndexLists, tablesPerStream, streamJoinAnalysisResult, statementRawInfo, services); QueryPlanNodeForge queryPlanNode = desc.Forge; additionalForgeables.AddAll(desc.AdditionalForgeables); if (Log.IsDebugEnabled) { Log.Debug( ".build spec for stream '" + streamNames[streamNo] + "' number " + streamNo + " is " + queryPlanNode); } planNodeSpecs[streamNo] = queryPlanNode; } var queryPlan = new QueryPlanForge(indexSpecs, planNodeSpecs); if (Log.IsDebugEnabled) { Log.Debug(".build query plan=" + queryPlan); } return new QueryPlanForgeDesc(queryPlan, additionalForgeables); }