/** * Walk the tree pre-order, finding all access nodes that are candidates and adding them to the * matches list. * * @param metadata Metadata implementation * @param node Root node to search * @param matches Collection to accumulate matches in * @throws TeiidComponentException * @throws QueryMetadataException */ List<CandidateJoin> findCandidate( PlanNode root, QueryMetadataInterface metadata, AnalysisRecord analysisRecord) throws QueryMetadataException, TeiidComponentException { List<CandidateJoin> candidates = new ArrayList<CandidateJoin>(); for (PlanNode joinNode : NodeEditor.findAllNodes(root, NodeConstants.Types.JOIN, NodeConstants.Types.ACCESS)) { CandidateJoin candidate = null; for (Iterator<PlanNode> j = joinNode.getChildren().iterator(); j.hasNext(); ) { PlanNode child = j.next(); child = FrameUtil.findJoinSourceNode(child); if (child.hasBooleanProperty(NodeConstants.Info.MAKE_NOT_DEP) || !isValidJoin(joinNode, child, analysisRecord)) { continue; } if (candidate == null) { candidate = new CandidateJoin(); candidate.joinNode = joinNode; candidates.add(candidate); } if (j.hasNext()) { candidate.leftCandidate = true; } else { candidate.rightCandidate = true; } } } return candidates; }
private RelationalNode convertPlan(PlanNode planNode) throws TeiidComponentException, TeiidProcessingException { // Convert current node in planTree RelationalNode convertedNode = convertNode(planNode); if (convertedNode == null) { Assertion.assertTrue(planNode.getChildCount() == 1); return convertPlan(planNode.getFirstChild()); } RelationalNode nextParent = convertedNode; // convertedNode may be the head of 1 or more nodes - go to end of chain while (nextParent.getChildren()[0] != null) { nextParent = nextParent.getChildren()[0]; } // Call convertPlan recursively on children for (PlanNode childNode : planNode.getChildren()) { RelationalNode child = convertPlan(childNode); if (planNode.getType() == NodeConstants.Types.SET_OP && nextParent instanceof UnionAllNode && childNode.getProperty(Info.SET_OPERATION) == childNode.getProperty(Info.SET_OPERATION) && childNode.getType() == NodeConstants.Types.SET_OP && childNode.hasBooleanProperty(Info.USE_ALL)) { for (RelationalNode grandChild : child.getChildren()) { if (grandChild != null) { nextParent.addChild(grandChild); } } } else { nextParent.addChild(child); } } // Return root of tree for top node return convertedNode; }
private PlanNode optimizeSorts( boolean parentBlocking, PlanNode node, PlanNode root, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, AnalysisRecord record, CommandContext context) throws QueryMetadataException, TeiidComponentException, QueryPlannerException { node = NodeEditor.findNodePreOrder( node, NodeConstants.Types.SORT | NodeConstants.Types.DUP_REMOVE | NodeConstants.Types.GROUP | NodeConstants.Types.JOIN | NodeConstants.Types.SET_OP, NodeConstants.Types.ACCESS); if (node == null) { return root; } switch (node.getType()) { case NodeConstants.Types.SORT: parentBlocking = true; if (node.hasBooleanProperty(NodeConstants.Info.IS_DUP_REMOVAL)) { break; } if (mergeSortWithDupRemoval(node)) { node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true); } else { root = checkForProjectOptimization(node, root, metadata, capFinder, record, context); if (NodeEditor.findParent(node, NodeConstants.Types.ACCESS) != null) { return root; } } OrderBy orderBy = (OrderBy) node.getProperty(NodeConstants.Info.SORT_ORDER); List<Expression> orderColumns = orderBy.getSortKeys(); List<Expression> sortExpressions = new ArrayList<Expression>(orderColumns.size()); PlanNode possibleSort = NodeEditor.findNodePreOrder( node, NodeConstants.Types.GROUP, NodeConstants.Types.SOURCE | NodeConstants.Types.ACCESS); if (possibleSort != null && !possibleSort.hasBooleanProperty(Info.ROLLUP)) { boolean otherExpression = false; SymbolMap groupMap = (SymbolMap) possibleSort.getProperty(Info.SYMBOL_MAP); for (Expression singleElementSymbol : orderColumns) { Expression ex = SymbolMap.getExpression(singleElementSymbol); if (ex instanceof ElementSymbol) { sortExpressions.add(groupMap.getMappedExpression((ElementSymbol) ex)); } else { otherExpression = true; break; } } List<Expression> exprs = (List<Expression>) possibleSort.getProperty(Info.GROUP_COLS); if (!otherExpression && exprs != null && exprs.containsAll(sortExpressions)) { exprs.removeAll(sortExpressions); exprs.addAll(0, sortExpressions); if (node.getParent() == null) { root = node.getFirstChild(); root.removeFromParent(); node = root; } else { PlanNode nextNode = node.getFirstChild(); NodeEditor.removeChildNode(node.getParent(), node); node = nextNode; } possibleSort.setProperty(Info.SORT_ORDER, orderBy); } } break; case NodeConstants.Types.DUP_REMOVE: if (parentBlocking) { node.setType(NodeConstants.Types.SORT); node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true); } break; case NodeConstants.Types.GROUP: if (!node.hasCollectionProperty(NodeConstants.Info.GROUP_COLS)) { break; } SymbolMap map = (SymbolMap) node.getProperty(Info.SYMBOL_MAP); boolean cardinalityDependent = false; boolean canOptimize = true; for (Expression ex : map.asMap().values()) { if (ex instanceof AggregateSymbol) { AggregateSymbol agg = (AggregateSymbol) ex; if (agg.isCardinalityDependent()) { cardinalityDependent = true; break; } } else if (!(ex instanceof ElementSymbol)) { // there is an expression in the grouping columns canOptimize = false; break; } } if (canOptimize && mergeSortWithDupRemovalAcrossSource(node)) { node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true); if (cardinalityDependent) { PlanNode source = NodeEditor.findNodePreOrder(node, NodeConstants.Types.SOURCE); List<Expression> sourceOutput = (List<Expression>) source.getProperty(Info.OUTPUT_COLS); PlanNode child = node.getFirstChild(); while (child != source) { child.setProperty(Info.OUTPUT_COLS, sourceOutput); child = child.getFirstChild(); } } } // TODO: check the join interesting order parentBlocking = true; break; case NodeConstants.Types.JOIN: if (node.getProperty(NodeConstants.Info.JOIN_STRATEGY) == JoinStrategyType.NESTED_LOOP || node.getProperty(NodeConstants.Info.JOIN_STRATEGY) == JoinStrategyType.NESTED_TABLE) { break; } /* * Look under the left and the right sources for a dup removal operation * join * [project] * source * dup remove | union not all */ parentBlocking = true; PlanNode toTest = node.getFirstChild(); if (mergeSortWithDupRemovalAcrossSource(toTest)) { node.setProperty(NodeConstants.Info.SORT_LEFT, SortOption.SORT_DISTINCT); if (node.getProperty(NodeConstants.Info.SORT_RIGHT) != SortOption.SORT) { node.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE); } } toTest = node.getLastChild(); if (mergeSortWithDupRemovalAcrossSource(toTest)) { node.setProperty(NodeConstants.Info.SORT_RIGHT, SortOption.SORT_DISTINCT); if (node.getProperty(NodeConstants.Info.SORT_LEFT) != SortOption.SORT) { node.setProperty(NodeConstants.Info.JOIN_STRATEGY, JoinStrategyType.MERGE); } } break; case NodeConstants.Types.SET_OP: // assumes the use of the merge algorithm if (node.getProperty(NodeConstants.Info.SET_OPERATION) != SetQuery.Operation.UNION) { parentBlocking = true; } else if (!node.hasBooleanProperty(NodeConstants.Info.USE_ALL) && !parentBlocking) { // do the incremental dup removal for lower latency node.setProperty(NodeConstants.Info.IS_DUP_REMOVAL, true); } break; } for (PlanNode child : node.getChildren()) { root = optimizeSorts(parentBlocking, child, root, metadata, capFinder, record, context); } return root; }