Search in sources :

Example 6 with OptimizablePredicate

use of org.apache.derby.iapi.sql.compile.OptimizablePredicate in project derby by apache.

the class SetOperatorNode method pushOptPredicate.

/**
 * @see org.apache.derby.iapi.sql.compile.Optimizable#pushOptPredicate
 *
 * Take a predicate and push it down to both the left AND right result
 * sets.  Return "true" if we successfully pushed it to both sides,
 * and "false" otherwise.  The assumption is that if we return "true",
 * the caller will take the predicate and remove it from its own list
 * of predicates to evaluate; if we return false, then the predicate
 * will be evaluated at the level of the caller.  So returning "false"
 * means that the left and right result sets for this node will be fully
 * returned, and then the predicate will be evaluated against the
 * <set-operator> of those result sets (as of DERBY-805, the only set
 * operator calling this method is UnionNode).  If we can push the
 * predicate down to both children, though, we can evaluate it closer
 * to store, which means that each child result set returns only the
 * correctly qualified rows, and thus the calling set operator will
 * have a smaller result set on which to operate, which can boost
 * performance.
 *
 * That said, if we can't push the predicate to _both_ sides, we don't
 * push it at all.  The reason is that if we push to one side but not
 * to the other, we would have to ask the question of whether we should
 * return "true" (meaning that the predicate would be removed from the
 * caller's list and thus would _not_ be evaluated at the <set-operator>
 * level) or "false" (meaning that the caller would keep the predicate
 * and evaluate it at the <set-operator> level).  Depending on the query
 * in question, both answers could end up returning incorrect results.
 *
 * For example, if we push it to the right but not to the left, then
 * leave it in the caller's list, the optimizer for the caller might
 * decide to use the predicate to do a hash join with some outer result
 * set (if the predicate is an equijoin predicate).  That would result
 * in materialization of the calling node and of its children--but since
 * we pushed a predicate that depends on the outer table down into the
 * right child, materialization of the right child will only return the
 * rows that join with the _first_ row of the outer result set, which
 * is wrong.
 *
 * If, on the other hand, we push the predicate to one side and then tell
 * the caller to remove it from its list, the side to which we did _not_
 * push the predicate could return rows that aren't qualified.  Then,
 * since the caller removed the predicate from its list, it (the caller)
 * will not evaluate the predicate on its own result set--and thus we
 * can end up returning rows that we weren't supposed to return.
 *
 * So all of that said, only push (and return "true") if we think we
 * can push the predicate to both sides.
 *
 * @exception StandardException		Thrown on error
 */
@Override
public boolean pushOptPredicate(OptimizablePredicate optimizablePredicate) throws StandardException {
    // when support for other SetOperators is added.
    if (!(this instanceof UnionNode))
        return false;
    // We only handle certain types of predicates here; if the received
    // predicate doesn't qualify, then don't push it.
    Predicate pred = (Predicate) optimizablePredicate;
    if (!pred.pushableToSubqueries())
        return false;
    // Check to see if the child nodes reference any base tables; if either
    // child does not reference at least one base table, then we don't try
    // to push the predicate.
    JBitSet tableNums = new JBitSet(getReferencedTableMap().size());
    BaseTableNumbersVisitor btnVis = new BaseTableNumbersVisitor(tableNums);
    // Check the left child.
    leftResultSet.accept(btnVis);
    boolean canPush = (tableNums.getFirstSetBit() != -1);
    /* If we can't push it to _both_ children, then we don't push at all.
		 * RESOLVE: We can add the ability to push a predicate to one side
		 * only by putting a ProjectRestrictNode between the union node and
		 * the child as a place to park the predicate. To make things simple,
		 * we might want to always put ProjectRestrictNodes under both sides
		 * of the union during preprocessing (i.e. after binding but before
		 * optimization). In some cases the extra nodes won't be needed, but
		 * PRNs (and the corresponding ProjectRestrictResultSets) are cheap.
		 * Also, we could eliminate unnecessary ProjectRestrictNodes at the
		 * end of optimization (possibly in modifyAccessPaths()).  Until all
		 * of that is implemented, though, we only push if we can push to
		 * both sides...
		 */
    if (!canPush)
        return false;
    // Check the right child.
    tableNums.clearAll();
    rightResultSet.accept(btnVis);
    canPush = (tableNums.getFirstSetBit() != -1);
    if (!canPush)
        return false;
    // Get a list of all of the underlying base tables that this node
    // references.  We pass this down when scoping so that we can tell
    // if the operands are actually supposed to be scoped to _this_
    // node's children.  Note that in order for the predicate to
    // have been pushed this far, at least one of its operands must
    // apply to this node--we don't know which one it is, though,
    // so we use this tableNums info to figure that out.
    tableNums.clearAll();
    this.accept(btnVis);
    /* What we want to do here is push the predicate to the left/right
		 * child.  That means that we need to find the equivalent column(s)
		 * in each child.
		 * Ex:
		 * 
		 *  select * from
		 *    (select i,j from t1 union select i,j from t2) X1,
		 *    (select a,b from t3 union select a,b from t4) X2
		 *  where X1.j = X2.b;
		 *
		 * In this example, X1.j maps to "t1" for the left side of the
		 * union (X1) and "t2" for the right side of the union.  So we have
		 * to get versions of the predicate that are appropriate to each
		 * side.  That's what the call to getPredScopedForResultSet()
		 * in the following code does.
		 */
    // For details on how this whichRC variable is used, see the
    // comments in BinaryRelationalOperatorNode.getScopedOperand().
    int[] whichRC = new int[] { -1 };
    // See if we already have a scoped version of the predicate cached,
    // and if so just use that.
    Predicate scopedPred = null;
    if (leftScopedPreds == null)
        leftScopedPreds = new HashMap<Predicate, Predicate>();
    else
        scopedPred = leftScopedPreds.get(pred);
    if (scopedPred == null) {
        scopedPred = pred.getPredScopedForResultSet(tableNums, leftResultSet, whichRC);
        leftScopedPreds.put(pred, scopedPred);
    }
    // Add the scoped predicate to our list for the left child.
    getLeftOptPredicateList().addOptPredicate(scopedPred);
    scopedPred = null;
    if (rightScopedPreds == null)
        rightScopedPreds = new HashMap<Predicate, Predicate>();
    else
        scopedPred = rightScopedPreds.get(pred);
    if (scopedPred == null) {
        scopedPred = pred.getPredScopedForResultSet(tableNums, rightResultSet, whichRC);
        rightScopedPreds.put(pred, scopedPred);
    }
    // Add the scoped predicate to our list for the right child.
    getRightOptPredicateList().addOptPredicate(scopedPred);
    // modifyAccessPaths() in this class for more.
    if (pushedPredicates == null)
        pushedPredicates = new PredicateList(getContextManager());
    pushedPredicates.addOptPredicate(pred);
    return true;
}
Also used : JBitSet(org.apache.derby.iapi.util.JBitSet) HashMap(java.util.HashMap) OptimizablePredicateList(org.apache.derby.iapi.sql.compile.OptimizablePredicateList) OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate)

Example 7 with OptimizablePredicate

use of org.apache.derby.iapi.sql.compile.OptimizablePredicate in project derby by apache.

the class NestedLoopJoinStrategy method putBasePredicates.

/**
 * @see JoinStrategy#putBasePredicates
 *
 * @exception StandardException		Thrown on error
 */
public void putBasePredicates(OptimizablePredicateList predList, OptimizablePredicateList basePredicates) throws StandardException {
    for (int i = basePredicates.size() - 1; i >= 0; i--) {
        OptimizablePredicate pred = basePredicates.getOptPredicate(i);
        predList.addOptPredicate(pred);
        basePredicates.removeOptPredicate(i);
    }
}
Also used : OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate)

Example 8 with OptimizablePredicate

use of org.apache.derby.iapi.sql.compile.OptimizablePredicate in project derby by apache.

the class HashJoinStrategy method getBasePredicates.

/**
 * @see JoinStrategy#getBasePredicates
 *
 * @exception StandardException		Thrown on error
 */
public OptimizablePredicateList getBasePredicates(OptimizablePredicateList predList, OptimizablePredicateList basePredicates, Optimizable innerTable) throws StandardException {
    if (SanityManager.DEBUG) {
        SanityManager.ASSERT(basePredicates.size() == 0, "The base predicate list should be empty.");
    }
    for (int i = predList.size() - 1; i >= 0; i--) {
        OptimizablePredicate pred = predList.getOptPredicate(i);
        if (innerTable.getReferencedTableMap().contains(pred.getReferencedMap())) {
            basePredicates.addOptPredicate(pred);
            predList.removeOptPredicate(i);
        }
    }
    basePredicates.classify(innerTable, innerTable.getCurrentAccessPath().getConglomerateDescriptor());
    return basePredicates;
}
Also used : OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate)

Example 9 with OptimizablePredicate

use of org.apache.derby.iapi.sql.compile.OptimizablePredicate in project derby by apache.

the class HashJoinStrategy method putBasePredicates.

/**
 * @see JoinStrategy#putBasePredicates
 *
 * @exception StandardException		Thrown on error
 */
public void putBasePredicates(OptimizablePredicateList predList, OptimizablePredicateList basePredicates) throws StandardException {
    for (int i = basePredicates.size() - 1; i >= 0; i--) {
        OptimizablePredicate pred = basePredicates.getOptPredicate(i);
        predList.addOptPredicate(pred);
        basePredicates.removeOptPredicate(i);
    }
}
Also used : OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate)

Aggregations

OptimizablePredicate (org.apache.derby.iapi.sql.compile.OptimizablePredicate)9 OptimizablePredicateList (org.apache.derby.iapi.sql.compile.OptimizablePredicateList)3 JBitSet (org.apache.derby.iapi.util.JBitSet)2 HashMap (java.util.HashMap)1 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)1 AccessPath (org.apache.derby.iapi.sql.compile.AccessPath)1 CostEstimate (org.apache.derby.iapi.sql.compile.CostEstimate)1 JoinStrategy (org.apache.derby.iapi.sql.compile.JoinStrategy)1 IndexRowGenerator (org.apache.derby.iapi.sql.dictionary.IndexRowGenerator)1 StoreCostController (org.apache.derby.iapi.store.access.StoreCostController)1 DataValueDescriptor (org.apache.derby.iapi.types.DataValueDescriptor)1