use of org.apache.derby.iapi.sql.compile.CostEstimate in project derby by apache.
the class SetOperatorNode method modifyAccessPath.
/**
* @see Optimizable#modifyAccessPath
*
* @exception StandardException Thrown on error
*/
public Optimizable modifyAccessPath(JBitSet outerTables, PredicateList predList) throws StandardException {
// is the equijoin predicate that is required by hash join.
if ((predList != null) && !getTrulyTheBestAccessPath().getJoinStrategy().isHashJoin()) {
for (int i = predList.size() - 1; i >= 0; i--) if (pushOptPredicate(predList.getOptPredicate(i)))
predList.removeOptPredicate(i);
}
/*
* It's possible that we tried to push a predicate down to this node's
* children but failed to do so. This can happen if this node's
* children both match the criteria for pushing a predicate (namely,
* they reference base tables) but the children's children do not.
* Ex.
* select * from
* (select i,j from t2 UNION
* values (1,1),(2,2),(3,3),(4,4) UNION
* select i,j from t1
* ) x0 (i,j),
* t5 where x0.i = t5.i;
*
* This will yield a tree resembling the following:
*
* UNION
* / \
* UNION SELECT (T1)
* / \
* SELECT (T2) VALUES
*
* In this case the top UNION ("this") will push the predicate down,
* but the second UNION will _not_ push the predicate because
* it can't be pushed to the VALUES clause. This means that
* after we're done modifying the paths for "this" node (the top
* UNION), the predicate will still be sitting in our leftOptPredicates
* list. If that's the case, then we have to make sure the predicate,
* which was _not_ enforced in the left child, is enforced at this
* level. We do that by generating a ProjectRestrictNode above this
* node. Yes, this means the predicate will actually be applied
* twice to the right child (in this case), but that's okay as it
* won't affect the results.
*/
// Get the cost estimate for this node so that we can put it in
// the new ProjectRestrictNode, if one is needed.
CostEstimate ce = getFinalCostEstimate();
// Modify this node's access paths.
ResultSetNode topNode = (ResultSetNode) modifyAccessPath(outerTables);
/* Now see if there are any left over predicates; if so, then we
* have to generate a ProjectRestrictNode. Note: we want to check
* all SetOpNodes that exist in the subtree rooted at this SetOpNode.
* Since we just modified access paths on this node, it's possible
* that the SetOperatorNode chain (if there was one) is now "broken"
* as a result of the insertion of new nodes. For example, prior
* to modification of access paths we may have a chain such as:
*
* UnionNode (0)
* / \
* UnionNode (1) SelectNode (2)
* / \
* SelectNode (3) SelectNode (4)
*
* Now if UnionNode(1) did not specify "ALL" then as part of the
* above call to modifyAccessPaths() we will have inserted a
* DistinctNode above it, thus giving:
*
* UnionNode (0)
* / \
* DistinctNode (5) SelectNode (2)
* |
* UnionNode (1)
* / \
* SelectNode (3) SelectNode (4)
*
* So our chain of UnionNode's has now been "broken" by an intervening
* DistinctNode. For this reason we can't just walk the chain of
* SetOperatorNodes looking for unpushed predicates (because the
* chain might be broken and then we could miss some nodes). Instead,
* we have to get a collection of all relevant nodes that exist beneath
* this SetOpNode and call hasUnPushedPredicates() on each one. For
* now we only consider UnionNodes to be "relevant" because those are
* the only ones that might actually have unpushed predicates.
*
* If we find any UnionNodes that *do* have unpushed predicates then
* we have to use a PRN to enforce the predicate at the level of
* this, the top-most, SetOperatorNode.
*/
// Find all UnionNodes in the subtree.
CollectNodesVisitor<UnionNode> cnv = new CollectNodesVisitor<UnionNode>(UnionNode.class);
this.accept(cnv);
// Now see if any of them have unpushed predicates.
boolean genPRN = false;
for (UnionNode node : cnv.getList()) {
if (node.hasUnPushedPredicates()) {
genPRN = true;
break;
}
}
if (genPRN) {
// When we generate the project restrict node, we pass in the
// "pushedPredicates" list because that has the predicates in
// _unscoped_ form, which means they are intended for _this_
// node instead of this node's children. That's exactly what
// we want.
ResultSetNode prnRSN = new ProjectRestrictNode(// Child ResultSet
topNode, // Projection
topNode.getResultColumns(), // Restriction
null, // Restriction as PredicateList
pushedPredicates, // Subquerys in Projection
null, // Subquerys in Restriction
null, // Table properties
null, getContextManager());
prnRSN.setCostEstimate(ce.cloneMe());
prnRSN.setReferencedTableMap(topNode.getReferencedTableMap());
topNode = prnRSN;
}
return (Optimizable) topNode;
}
use of org.apache.derby.iapi.sql.compile.CostEstimate in project derby by apache.
the class DistinctNode method estimateCost.
/**
* @see Optimizable#estimateCost
*
* @exception StandardException Thrown on error
*/
@Override
public CostEstimate estimateCost(OptimizablePredicateList predList, ConglomerateDescriptor cd, CostEstimate outerCost, Optimizer optimizer, RowOrdering rowOrdering) throws StandardException {
// RESOLVE: WE NEED TO ADD IN THE COST OF SORTING HERE, AND FIGURE
// OUT HOW MANY ROWS WILL BE ELIMINATED.
CostEstimate childCost = ((Optimizable) childResult).estimateCost(predList, cd, outerCost, optimizer, rowOrdering);
setCostEstimate(getCostEstimate(optimizer));
getCostEstimate().setCost(childCost.getEstimatedCost(), childCost.rowCount(), childCost.singleScanRowCount());
/*
** No need to use estimateCost on join strategy - that has already
** been done on the child.
*/
return getCostEstimate();
}
use of org.apache.derby.iapi.sql.compile.CostEstimate in project derby by apache.
the class FromBaseTable method generateMaxSpecialResultSet.
private void generateMaxSpecialResultSet(ExpressionClassBuilder acb, MethodBuilder mb) throws StandardException {
ConglomerateDescriptor cd = getTrulyTheBestAccessPath().getConglomerateDescriptor();
CostEstimate costEst = getFinalCostEstimate();
int colRefItem = (referencedCols == null) ? -1 : acb.addItem(referencedCols);
boolean tableLockGranularity = tableDescriptor.getLockGranularity() == TableDescriptor.TABLE_LOCK_GRANULARITY;
/*
** getLastIndexKeyResultSet
** (
** activation,
** resultSetNumber,
** resultRowAllocator,
** conglomereNumber,
** tableName,
** optimizeroverride
** indexName,
** colRefItem,
** lockMode,
** tableLocked,
** isolationLevel,
** optimizerEstimatedRowCount,
** optimizerEstimatedRowCost,
** );
*/
acb.pushGetResultSetFactoryExpression(mb);
acb.pushThisAsActivation(mb);
mb.push(getResultSetNumber());
mb.push(acb.addItem(getResultColumns().buildRowTemplate(referencedCols, false)));
mb.push(cd.getConglomerateNumber());
mb.push(tableDescriptor.getName());
// run time statistics.
if (tableProperties != null)
mb.push(org.apache.derby.iapi.util.PropertyUtil.sortProperties(tableProperties));
else
mb.pushNull("java.lang.String");
pushIndexName(cd, mb);
mb.push(colRefItem);
mb.push(getTrulyTheBestAccessPath().getLockMode());
mb.push(tableLockGranularity);
mb.push(getCompilerContext().getScanIsolationLevel());
mb.push(costEst.singleScanRowCount());
mb.push(costEst.getEstimatedCost());
mb.callMethod(VMOpcode.INVOKEINTERFACE, (String) null, "getLastIndexKeyResultSet", ClassName.NoPutResultSet, 13);
}
use of org.apache.derby.iapi.sql.compile.CostEstimate in project derby by apache.
the class FromTable method startOptimizing.
/**
* @see Optimizable#startOptimizing
*/
public void startOptimizing(Optimizer optimizer, RowOrdering rowOrdering) {
resetJoinStrategies(optimizer);
considerSortAvoidancePath = false;
/*
** If there are costs associated with the best and sort access
** paths, set them to their maximum values, so that any legitimate
** access path will look cheaper.
*/
CostEstimate ce = getBestAccessPath().getCostEstimate();
if (ce != null)
ce.setCost(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
ce = getBestSortAvoidancePath().getCostEstimate();
if (ce != null)
ce.setCost(Double.MAX_VALUE, Double.MAX_VALUE, Double.MAX_VALUE);
if (!canBeOrdered())
rowOrdering.addUnorderedOptimizable(this);
}
use of org.apache.derby.iapi.sql.compile.CostEstimate in project derby by apache.
the class JoinNode method getFinalCostEstimate.
/**
* @see ResultSetNode#getFinalCostEstimate
*
* Get the final CostEstimate for this JoinNode.
*
* @return The final CostEstimate for this JoinNode, which is sum
* the costs for the inner and outer table. The number of rows,
* though, is that for the inner table only.
*/
@Override
CostEstimate getFinalCostEstimate() throws StandardException {
// If we already found it, just return it.
if (getCandidateFinalCostEstimate() != null) {
return getCandidateFinalCostEstimate();
}
CostEstimate leftCE = leftResultSet.getFinalCostEstimate();
CostEstimate rightCE = rightResultSet.getFinalCostEstimate();
setCandidateFinalCostEstimate(getNewCostEstimate());
getCandidateFinalCostEstimate().setCost(leftCE.getEstimatedCost() + rightCE.getEstimatedCost(), rightCE.rowCount(), rightCE.rowCount());
return getCandidateFinalCostEstimate();
}
Aggregations