Exemplo n.º 1
0
  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;
  }