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;
}
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);
}
}
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;
}
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);
}
}
Aggregations