Search in sources :

Example 51 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class JoinUtil method optimizeJoinType.

/**
 * Will attempt to optimize the join type based upon the criteria provided.
 *
 * Returns the new join type if one is found, otherwise null
 *
 * An outer join can be optimized if criteria that is not dependent upon null values
 * is applied on the inner side of the join.
 *
 * @param critNode
 * @param joinNode
 * @return
 */
static final JoinType optimizeJoinType(PlanNode critNode, PlanNode joinNode, QueryMetadataInterface metadata, boolean modifyJoin) {
    if (critNode.getGroups().isEmpty() || !joinNode.getGroups().containsAll(critNode.getGroups()) || joinNode.hasBooleanProperty(Info.PRESERVE)) {
        return null;
    }
    JoinType joinType = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
    if (!joinType.isOuter()) {
        return null;
    }
    PlanNode left = joinNode.getFirstChild();
    left = FrameUtil.findJoinSourceNode(left);
    PlanNode right = joinNode.getLastChild();
    right = FrameUtil.findJoinSourceNode(right);
    Collection<GroupSymbol> outerGroups = left.getGroups();
    Collection<GroupSymbol> innerGroups = right.getGroups();
    if (joinType == JoinType.JOIN_RIGHT_OUTER) {
        outerGroups = innerGroups;
        innerGroups = left.getGroups();
    }
    // sanity check
    if ((joinType == JoinType.JOIN_LEFT_OUTER || joinType == JoinType.JOIN_RIGHT_OUTER) && outerGroups.containsAll(critNode.getGroups())) {
        return null;
    }
    Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
    boolean isNullDepdendent = isNullDependent(metadata, innerGroups, crit);
    JoinType result = JoinType.JOIN_INNER;
    if (joinType == JoinType.JOIN_LEFT_OUTER || joinType == JoinType.JOIN_RIGHT_OUTER) {
        if (isNullDepdendent) {
            return null;
        }
    } else {
        boolean isNullDepdendentOther = isNullDependent(metadata, outerGroups, crit);
        if (isNullDepdendent && isNullDepdendentOther) {
            return null;
        }
        if (isNullDepdendent && !isNullDepdendentOther) {
            result = JoinType.JOIN_LEFT_OUTER;
        } else if (!isNullDepdendent && isNullDepdendentOther) {
            if (modifyJoin) {
                JoinUtil.swapJoinChildren(joinNode);
                result = JoinType.JOIN_LEFT_OUTER;
            }
        }
    }
    if (modifyJoin) {
        joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, result);
    }
    return result;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) JoinType(org.teiid.query.sql.lang.JoinType) Criteria(org.teiid.query.sql.lang.Criteria)

Example 52 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class JoinUtil method swapJoinChildren.

/**
 * @param joinNode
 */
static void swapJoinChildren(PlanNode joinNode) {
    PlanNode leftChild = joinNode.getFirstChild();
    joinNode.removeChild(leftChild);
    joinNode.addLastChild(leftChild);
    List leftExpressions = (List) joinNode.getProperty(NodeConstants.Info.LEFT_EXPRESSIONS);
    List rightExpressions = (List) joinNode.getProperty(NodeConstants.Info.RIGHT_EXPRESSIONS);
    joinNode.setProperty(NodeConstants.Info.LEFT_EXPRESSIONS, rightExpressions);
    joinNode.setProperty(NodeConstants.Info.RIGHT_EXPRESSIONS, leftExpressions);
    JoinType jt = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
    joinNode.setProperty(NodeConstants.Info.JOIN_TYPE, jt.getReverseType());
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) JoinType(org.teiid.query.sql.lang.JoinType) List(java.util.List)

Example 53 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class JoinUtil method getInnerSideJoinNodes.

/**
 * Can be called after join planning on a join node to get the inner sides of the join
 * @param joinNode
 * @return
 */
static PlanNode[] getInnerSideJoinNodes(PlanNode joinNode) {
    Assertion.assertTrue(joinNode.getType() == NodeConstants.Types.JOIN);
    JoinType jt = (JoinType) joinNode.getProperty(NodeConstants.Info.JOIN_TYPE);
    if (jt == JoinType.JOIN_INNER || jt == JoinType.JOIN_CROSS) {
        return new PlanNode[] { joinNode.getFirstChild(), joinNode.getLastChild() };
    }
    if (jt == JoinType.JOIN_RIGHT_OUTER) {
        return new PlanNode[] { joinNode.getFirstChild() };
    }
    if (jt == JoinType.JOIN_LEFT_OUTER) {
        return new PlanNode[] { joinNode.getLastChild() };
    }
    // must be full outer, so there is no inner side
    return new PlanNode[] {};
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) JoinType(org.teiid.query.sql.lang.JoinType)

Example 54 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class NewCalculateCostUtil method getNDVEstimate.

/**
 * @param indNode
 * @param metadata
 * @param cardinality
 * @param elems
 * @param useCardinalityIfUnknown - false is a low estimate, null uses a middle estimate, and true uses a high estimate
 * @return
 * @throws QueryMetadataException
 * @throws TeiidComponentException
 */
static float getNDVEstimate(PlanNode indNode, QueryMetadataInterface metadata, float cardinality, Collection<? extends Expression> elems, Boolean useCardinalityIfUnknown) throws QueryMetadataException, TeiidComponentException {
    if (elems == null || elems.isEmpty()) {
        return cardinality;
    }
    float ndv = getStat(Stat.NDV, elems, indNode, cardinality, metadata);
    // if we're using cardinality, then we want to include the high estimate
    if (ndv != UNKNOWN_VALUE && (useCardinalityIfUnknown == null || useCardinalityIfUnknown)) {
        float ndv_high = getStat(Stat.NDV_HIGH, elems, indNode, cardinality, metadata);
        if (ndv_high != UNKNOWN_VALUE) {
            if (useCardinalityIfUnknown == null) {
                ndv = (float) Math.sqrt(ndv * ndv_high);
            } else {
                ndv = (ndv + ndv_high) / 2;
            }
        }
    }
    // special handling if cardinality has been set, but not ndv
    if (ndv == UNKNOWN_VALUE && (useCardinalityIfUnknown == null || useCardinalityIfUnknown)) {
        Set<GroupSymbol> groups = GroupsUsedByElementsVisitor.getGroups(elems);
        PlanNode source = FrameUtil.findOriginatingNode(indNode, groups);
        if (source != null) {
            ndv = getStat(Stat.NDV, elems, source, source.getCardinality(), metadata);
            if (ndv == UNKNOWN_VALUE) {
                if (useCardinalityIfUnknown != null || source.getChildCount() == 0) {
                    ndv = source.getCardinality();
                }
                if (ndv != UNKNOWN_VALUE && !usesKey(source, elems, metadata)) {
                    // guess that it's non-unique
                    ndv /= 2;
                }
            }
            if (ndv != UNKNOWN_VALUE) {
                while (source != indNode) {
                    source = source.getParent();
                    float parentCardinality = source.getCardinality();
                    if (parentCardinality != UNKNOWN_VALUE && parentCardinality < ndv) {
                        ndv = parentCardinality;
                    }
                }
            }
        }
    }
    if (ndv == UNKNOWN_VALUE) {
        if (cardinality == UNKNOWN_VALUE) {
            return UNKNOWN_VALUE;
        }
        if (usesKey(indNode, elems, metadata)) {
            ndv = cardinality;
        } else if (useCardinalityIfUnknown != null && useCardinalityIfUnknown) {
            ndv = cardinality / 2;
        } else {
            return UNKNOWN_VALUE;
        }
    }
    if (cardinality != UNKNOWN_VALUE && cardinality < ndv) {
        ndv = cardinality;
    }
    return Math.max(1, ndv);
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol)

Example 55 with PlanNode

use of org.teiid.query.optimizer.relational.plantree.PlanNode in project teiid by teiid.

the class NewCalculateCostUtil method estimateSourceNodeCost.

/**
 * For a source node, the cost is basically the cardinality of the source
 * (if it is known).
 * @param node
 * @param metadata
 * @throws QueryMetadataException
 * @throws TeiidComponentException
 */
private static void estimateSourceNodeCost(PlanNode node, QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
    float cost = UNKNOWN_VALUE;
    if (node.getChildCount() > 0) {
        SymbolMap references = (SymbolMap) node.getProperty(NodeConstants.Info.CORRELATED_REFERENCES);
        // only cost non-correlated TODO: a better estimate for correlated
        if (references == null) {
            PlanNode child = node.getFirstChild();
            cost = child.getCardinality();
            SymbolMap symbolMap = (SymbolMap) node.getProperty(NodeConstants.Info.SYMBOL_MAP);
            if (symbolMap != null) {
                ColStats colStats = (ColStats) child.getProperty(Info.EST_COL_STATS);
                if (colStats != null) {
                    List<? extends Expression> outputCols = getOutputCols(node, metadata);
                    ColStats newColStats = new ColStats();
                    for (Expression expr : outputCols) {
                        if (!(expr instanceof ElementSymbol)) {
                            continue;
                        }
                        ElementSymbol es = (ElementSymbol) expr;
                        Expression ex = symbolMap.getMappedExpression(es);
                        float[] value = colStats.get(ex);
                        if (value == null) {
                            Collection<ElementSymbol> elems = ElementCollectorVisitor.getElements(ex, true);
                            value = new float[3];
                            value[Stat.NDV.ordinal()] = getStat(Stat.NDV, elems, node, cost, metadata);
                            value[Stat.NDV_HIGH.ordinal()] = getStat(Stat.NDV_HIGH, elems, node, cost, metadata);
                            value[Stat.NNV.ordinal()] = getStat(Stat.NNV, elems, node, cost, metadata);
                        }
                        newColStats.put(es, value);
                    }
                    node.setProperty(Info.EST_COL_STATS, newColStats);
                } else {
                    colStats = createColStats(node, metadata, cost);
                    node.setProperty(Info.EST_COL_STATS, colStats);
                }
            }
        }
    } else {
        GroupSymbol group = node.getGroups().iterator().next();
        float cardinality = metadata.getCardinality(group.getMetadataID());
        if (cardinality <= QueryMetadataInterface.UNKNOWN_CARDINALITY) {
            if (group.isTempTable() && metadata.getModelID(group.getMetadataID()) == TempMetadataAdapter.TEMP_MODEL) {
                // this should be with-in the scope of a procedure or an undefined size common table
                // 
                // the typical assumption is that this should drive other joins, thus assume
                // a relatively small number of rows.  This is a relatively safe assumption
                // as we do not need parallel processing with the temp fetch and the
                // dependent join backoff should prevent unacceptable performance
                // 
                // another strategy (that is generally applicable) is to delay the full affect of dependent join planning
                // until the size is known - however that is somewhat complicated with the current WITH logic
                // as the table is loaded on demand
                cardinality = BufferManager.DEFAULT_PROCESSOR_BATCH_SIZE;
            } else {
                cardinality = UNKNOWN_VALUE;
            }
        }
        cost = cardinality;
        if (!node.hasProperty(Info.ATOMIC_REQUEST)) {
            ColStats colStats = createColStats(node, metadata, cost);
            node.setProperty(Info.EST_COL_STATS, colStats);
        }
    }
    setCardinalityEstimate(node, new Float(cost), false, metadata);
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol) SymbolMap(org.teiid.query.sql.util.SymbolMap)

Aggregations

PlanNode (org.teiid.query.optimizer.relational.plantree.PlanNode)204 Expression (org.teiid.query.sql.symbol.Expression)50 GroupSymbol (org.teiid.query.sql.symbol.GroupSymbol)50 ArrayList (java.util.ArrayList)47 List (java.util.List)43 SymbolMap (org.teiid.query.sql.util.SymbolMap)42 ElementSymbol (org.teiid.query.sql.symbol.ElementSymbol)36 Criteria (org.teiid.query.sql.lang.Criteria)35 LinkedList (java.util.LinkedList)24 CompareCriteria (org.teiid.query.sql.lang.CompareCriteria)24 Test (org.junit.Test)22 HashSet (java.util.HashSet)17 JoinType (org.teiid.query.sql.lang.JoinType)17 LinkedHashSet (java.util.LinkedHashSet)16 CompoundCriteria (org.teiid.query.sql.lang.CompoundCriteria)12 DependentSetCriteria (org.teiid.query.sql.lang.DependentSetCriteria)12 QueryPlannerException (org.teiid.api.exception.query.QueryPlannerException)11 LanguageObject (org.teiid.query.sql.LanguageObject)11 OrderBy (org.teiid.query.sql.lang.OrderBy)10 IsNullCriteria (org.teiid.query.sql.lang.IsNullCriteria)9