Search in sources :

Example 46 with PlanNode

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

the class JoinRegion method scoreRegion.

/**
 * Will provide an estimate of cost by summing the estimated tuples flowing through
 * each intermediate join.
 *
 * @param joinOrder
 * @param metadata
 * @return
 * @throws TeiidComponentException
 * @throws QueryMetadataException
 * @throws QueryPlannerException
 */
public double scoreRegion(Object[] joinOrder, int startIndex, QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context, boolean partial) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    List<Map.Entry<PlanNode, PlanNode>> joinSourceEntries = new ArrayList<Map.Entry<PlanNode, PlanNode>>(joinSourceNodes.entrySet());
    double totalIntermediatCost = 0;
    double cost = 1;
    HashSet<PlanNode> criteria = new HashSet<PlanNode>(this.criteriaNodes);
    HashSet<GroupSymbol> groups = new HashSet<GroupSymbol>(this.joinSourceNodes.size());
    HashSet<GroupSymbol> rightGroups = new HashSet<GroupSymbol>();
    List<Expression> leftExpressions = new ArrayList<Expression>();
    List<Expression> rightExpressions = new ArrayList<Expression>();
    HashSet<Criteria> nonEquiJoinCriteria = new HashSet<Criteria>();
    // only calculate up to the second to last as the last is not an intermediate result
    for (int i = 0; i < joinOrder.length - (partial ? 0 : 1); i++) {
        boolean hasUnknown = false;
        boolean shouldFilter = true;
        Integer source = (Integer) joinOrder[i];
        Map.Entry<PlanNode, PlanNode> entry = joinSourceEntries.get(source.intValue());
        PlanNode joinSourceRoot = entry.getValue();
        if (i >= startIndex) {
            // check to make sure that this group ordering satisfies the access patterns
            if (!this.unsatisfiedAccessPatterns.isEmpty() || this.containsNestedTable) {
                PlanNode joinSource = entry.getKey();
                Collection<GroupSymbol> requiredGroups = (Collection<GroupSymbol>) joinSource.getProperty(NodeConstants.Info.REQUIRED_ACCESS_PATTERN_GROUPS);
                if (requiredGroups != null && !groups.containsAll(requiredGroups)) {
                    return Double.MAX_VALUE;
                }
            }
        }
        rightGroups.clear();
        rightGroups.addAll(groups);
        groups.addAll(joinSourceRoot.getGroups());
        if (startIndex > 0 && i < startIndex) {
            continue;
        }
        float sourceCost = joinSourceRoot.getCardinality();
        List<PlanNode> applicableCriteria = null;
        CompoundCriteria cc = null;
        if (!criteria.isEmpty() && i > 0) {
            applicableCriteria = getJoinCriteriaForGroups(groups, criteria);
            if (applicableCriteria != null && !applicableCriteria.isEmpty()) {
                cc = new CompoundCriteria();
                for (PlanNode planNode : applicableCriteria) {
                    cc.addCriteria((Criteria) planNode.getProperty(NodeConstants.Info.SELECT_CRITERIA));
                }
            }
        }
        if (sourceCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
            sourceCost = UNKNOWN_TUPLE_EST;
            hasUnknown = true;
            if (cc != null) {
                shouldFilter = false;
                sourceCost = (float) cost;
                criteria.removeAll(applicableCriteria);
                if (NewCalculateCostUtil.usesKey(cc, metadata) || (i >= 1 && joinSourceRoot.hasProperty(Info.MAKE_DEP) && !joinSourceRoot.hasBooleanProperty(Info.MAKE_NOT_DEP))) {
                    sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * Math.min(NewCalculateCostUtil.UNKNOWN_JOIN_SCALING, sourceCost));
                } else {
                    sourceCost = Math.min(UNKNOWN_TUPLE_EST, sourceCost * NewCalculateCostUtil.UNKNOWN_JOIN_SCALING * 8);
                }
            }
        } else if (Double.isInfinite(sourceCost) || Double.isNaN(sourceCost)) {
            return Double.MAX_VALUE;
        } else if (i == 1 && applicableCriteria != null && !applicableCriteria.isEmpty()) {
            List<Object> key = Arrays.asList(joinOrder[0], joinOrder[1]);
            Float depJoinCost = null;
            if (depCache != null && depCache.containsKey(key)) {
                depJoinCost = depCache.get(key);
            } else {
                Integer indIndex = (Integer) joinOrder[0];
                Map.Entry<PlanNode, PlanNode> indEntry = joinSourceEntries.get(indIndex.intValue());
                PlanNode possibleInd = indEntry.getValue();
                depJoinCost = getDepJoinCost(metadata, capFinder, context, possibleInd, applicableCriteria, joinSourceRoot);
                if (depCache == null) {
                    depCache = new HashMap<List<Object>, Float>();
                }
                depCache.put(key, depJoinCost);
            }
            if (depJoinCost != null) {
                sourceCost = depJoinCost;
            }
        }
        if (i > 0 && (applicableCriteria == null || applicableCriteria.isEmpty()) && hasUnknown) {
            // cross join penalty
            sourceCost *= 10;
        }
        double rightCost = cost;
        cost *= sourceCost;
        if (cc != null && applicableCriteria != null && shouldFilter) {
            // filter based upon notion of join
            leftExpressions.clear();
            rightExpressions.clear();
            nonEquiJoinCriteria.clear();
            Collection<GroupSymbol> leftGroups = joinSourceRoot.getGroups();
            RuleChooseJoinStrategy.separateCriteria(leftGroups, rightGroups, leftExpressions, rightExpressions, cc.getCriteria(), nonEquiJoinCriteria);
            if (!leftExpressions.isEmpty()) {
                float leftNdv = NewCalculateCostUtil.getNDVEstimate(joinSourceRoot, metadata, sourceCost, leftExpressions, null);
                float rightNdv = NewCalculateCostUtil.UNKNOWN_VALUE;
                if (leftNdv != NewCalculateCostUtil.UNKNOWN_VALUE) {
                    Set<GroupSymbol> usedRight = GroupsUsedByElementsVisitor.getGroups(rightExpressions);
                    for (int j = 0; j < i; j++) {
                        Entry<PlanNode, PlanNode> previousEntry = joinSourceEntries.get((int) joinOrder[j]);
                        if (previousEntry.getValue().getGroups().containsAll(usedRight)) {
                            rightNdv = NewCalculateCostUtil.getNDVEstimate(previousEntry.getValue(), metadata, sourceCost, rightExpressions, null);
                            break;
                        }
                    }
                }
                if (leftNdv != NewCalculateCostUtil.UNKNOWN_VALUE && rightNdv != NewCalculateCostUtil.UNKNOWN_VALUE) {
                    cost = (sourceCost / leftNdv) * (rightCost / rightNdv) * Math.min(leftNdv, rightNdv);
                } else {
                    // check for a key
                    // just use the default logic
                    nonEquiJoinCriteria.clear();
                }
            } else {
                // just use the default logic
                nonEquiJoinCriteria.clear();
            }
            for (PlanNode criteriaNode : applicableCriteria) {
                Criteria crit = (Criteria) criteriaNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
                if (!nonEquiJoinCriteria.contains(crit)) {
                    continue;
                }
                float filter = ((Float) criteriaNode.getProperty(NodeConstants.Info.EST_SELECTIVITY)).floatValue();
                cost *= filter;
            }
            criteria.removeAll(applicableCriteria);
        }
        totalIntermediatCost += cost;
    }
    return totalIntermediatCost;
}
Also used : CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) Entry(java.util.Map.Entry) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) Expression(org.teiid.query.sql.symbol.Expression) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol)

Example 47 with PlanNode

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

the class JoinRegion method initializeJoinInformation.

/**
 *  Initializes information on the joinRegion about dependency information, etc.
 *
 *  TODO: assumptions are made here about how dependent criteria must look that are a little restrictive
 */
public void initializeJoinInformation() {
    critieriaToSourceMap = new HashMap<PlanNode, Set<PlanNode>>();
    LinkedList<PlanNode> crits = new LinkedList<PlanNode>(criteriaNodes);
    crits.addAll(dependentCritieraNodes);
    LinkedHashMap<PlanNode, PlanNode> source = new LinkedHashMap<PlanNode, PlanNode>(joinSourceNodes);
    source.putAll(dependentJoinSourceNodes);
    for (PlanNode critNode : crits) {
        for (GroupSymbol group : critNode.getGroups()) {
            for (PlanNode node : source.keySet()) {
                if (node.getGroups().contains(group)) {
                    Set<PlanNode> sources = critieriaToSourceMap.get(critNode);
                    if (sources == null) {
                        sources = new HashSet<PlanNode>();
                        critieriaToSourceMap.put(critNode, sources);
                    }
                    sources.add(node);
                    break;
                }
            }
        }
    }
    if (unsatisfiedAccessPatterns.isEmpty()) {
        return;
    }
    Map<GroupSymbol, PlanNode> dependentGroupToSourceMap = new HashMap<GroupSymbol, PlanNode>();
    for (PlanNode node : dependentJoinSourceNodes.keySet()) {
        for (GroupSymbol symbol : node.getGroups()) {
            dependentGroupToSourceMap.put(symbol, node);
        }
    }
    for (Iterator<PlanNode> i = getCriteriaNodes().iterator(); i.hasNext(); ) {
        PlanNode node = i.next();
        for (GroupSymbol symbol : node.getGroups()) {
            if (dependentGroupToSourceMap.containsKey(symbol)) {
                i.remove();
                dependentCritieraNodes.add(node);
                break;
            }
        }
    }
    dependentCriteriaElements = new HashMap<ElementSymbol, Set<Collection<GroupSymbol>>>();
    for (PlanNode critNode : dependentCritieraNodes) {
        Criteria crit = (Criteria) critNode.getProperty(NodeConstants.Info.SELECT_CRITERIA);
        if (!(crit instanceof CompareCriteria)) {
            continue;
        }
        CompareCriteria compCrit = (CompareCriteria) crit;
        if (compCrit.getOperator() != CompareCriteria.EQ) {
            continue;
        }
        CompareCriteria compareCriteria = (CompareCriteria) crit;
        // this may be a proper dependent join criteria
        Collection<ElementSymbol>[] critElements = new Collection[2];
        critElements[0] = ElementCollectorVisitor.getElements(compareCriteria.getLeftExpression(), true);
        if (critElements[0].isEmpty()) {
            continue;
        }
        critElements[1] = ElementCollectorVisitor.getElements(compareCriteria.getRightExpression(), true);
        if (critElements[1].isEmpty()) {
            continue;
        }
        for (int expr = 0; expr < critElements.length; expr++) {
            // simplifying assumption that there will be a single element on the dependent side
            if (critElements[expr].size() != 1) {
                continue;
            }
            ElementSymbol elem = critElements[expr].iterator().next();
            if (!dependentGroupToSourceMap.containsKey(elem.getGroupSymbol())) {
                continue;
            }
            // this is also a simplifying assumption.  don't consider criteria that can't be pushed
            if (containsFunctionsThatCannotBePushed(expr == 0 ? compareCriteria.getRightExpression() : compareCriteria.getLeftExpression())) {
                continue;
            }
            Set<Collection<GroupSymbol>> independentGroups = dependentCriteriaElements.get(elem);
            if (independentGroups == null) {
                independentGroups = new HashSet<Collection<GroupSymbol>>();
                dependentCriteriaElements.put(elem, independentGroups);
            }
            // set the other side as independent elements
            independentGroups.add(GroupsUsedByElementsVisitor.getGroups(critElements[(expr + 1) % 2]));
        }
    }
}
Also used : ElementSymbol(org.teiid.query.sql.symbol.ElementSymbol) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria) PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) GroupSymbol(org.teiid.query.sql.symbol.GroupSymbol)

Example 48 with PlanNode

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

the class JoinRegion method reconstructJoinRegoin.

/**
 * This will rebuild the join tree starting at the join root.
 *
 * A left linear tree will be constructed out of the ordering of the
 * join sources.
 *
 * Criteria nodes are simply placed at the top of the join region in order
 * to be pushed by rule PushSelectSriteria.
 */
public void reconstructJoinRegoin() {
    LinkedHashMap<PlanNode, PlanNode> combined = new LinkedHashMap<PlanNode, PlanNode>(joinSourceNodes);
    combined.putAll(dependentJoinSourceNodes);
    PlanNode root = null;
    if (combined.size() < 2) {
        root = combined.values().iterator().next();
    } else {
        root = RulePlanJoins.createJoinNode();
        for (Map.Entry<PlanNode, PlanNode> entry : combined.entrySet()) {
            PlanNode joinSourceRoot = entry.getValue();
            if (root.getChildCount() == 2) {
                PlanNode parentJoin = RulePlanJoins.createJoinNode();
                parentJoin.addFirstChild(root);
                parentJoin.addGroups(root.getGroups());
                root = parentJoin;
            }
            root.addLastChild(joinSourceRoot);
            root.addGroups(entry.getKey().getGroups());
        }
    }
    LinkedList<PlanNode> criteria = new LinkedList<PlanNode>(dependentCritieraNodes);
    criteria.addAll(criteriaNodes);
    PlanNode parent = this.joinRoot.getParent();
    boolean isLeftChild = parent.getFirstChild() == this.joinRoot;
    parent.removeChild(joinRoot);
    for (PlanNode critNode : criteria) {
        critNode.removeFromParent();
        critNode.removeAllChildren();
        critNode.addFirstChild(root);
        root = critNode;
        critNode.removeProperty(NodeConstants.Info.IS_COPIED);
        critNode.removeProperty(NodeConstants.Info.EST_CARDINALITY);
    }
    if (isLeftChild) {
        parent.addFirstChild(root);
    } else {
        parent.addLastChild(root);
    }
    this.joinRoot = root;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode)

Example 49 with PlanNode

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

the class JoinRegion method getDepJoinCost.

private Float getDepJoinCost(QueryMetadataInterface metadata, CapabilitiesFinder capFinder, CommandContext context, PlanNode indNode, List<PlanNode> applicableCriteria, PlanNode depNode) throws QueryMetadataException, TeiidComponentException, QueryPlannerException {
    if (depNode.hasBooleanProperty(Info.MAKE_NOT_DEP)) {
        return null;
    }
    float indCost = indNode.getCardinality();
    if (indCost == NewCalculateCostUtil.UNKNOWN_VALUE) {
        return null;
    }
    List<Criteria> crits = new ArrayList<Criteria>(applicableCriteria.size());
    for (PlanNode planNode : applicableCriteria) {
        crits.add((Criteria) planNode.getProperty(NodeConstants.Info.SELECT_CRITERIA));
    }
    List<Expression> leftExpressions = new LinkedList<Expression>();
    List<Expression> rightExpressions = new LinkedList<Expression>();
    RuleChooseJoinStrategy.separateCriteria(indNode.getGroups(), depNode.getGroups(), leftExpressions, rightExpressions, crits, new LinkedList<Criteria>());
    if (leftExpressions.isEmpty()) {
        return null;
    }
    return NewCalculateCostUtil.computeCostForDepJoin(indNode, depNode, leftExpressions, rightExpressions, metadata, capFinder, context).expectedCardinality;
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) Expression(org.teiid.query.sql.symbol.Expression) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

Example 50 with PlanNode

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

the class JoinRegion method estimateCriteriaSelectivity.

/**
 * @param metadata
 * @throws QueryMetadataException
 * @throws TeiidComponentException
 */
private void estimateCriteriaSelectivity(QueryMetadataInterface metadata) throws QueryMetadataException, TeiidComponentException {
    for (PlanNode node : criteriaNodes) {
        Criteria crit = (Criteria) node.getProperty(NodeConstants.Info.SELECT_CRITERIA);
        float[] baseCosts = new float[] { 100, 10000, 1000000 };
        float filterValue = 0;
        for (int j = 0; j < baseCosts.length; j++) {
            float filter = NewCalculateCostUtil.recursiveEstimateCostOfCriteria(baseCosts[j], node, crit, metadata);
            filterValue += filter / baseCosts[j];
        }
        filterValue /= baseCosts.length;
        node.setProperty(NodeConstants.Info.EST_SELECTIVITY, new Float(filterValue));
    }
}
Also used : PlanNode(org.teiid.query.optimizer.relational.plantree.PlanNode) CompoundCriteria(org.teiid.query.sql.lang.CompoundCriteria) Criteria(org.teiid.query.sql.lang.Criteria) CompareCriteria(org.teiid.query.sql.lang.CompareCriteria)

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