use of org.apache.derby.iapi.sql.compile.Optimizable in project derby by apache.
the class XMLOptTrace method traceConsideringConglomerate.
public void traceConsideringConglomerate(ConglomerateDescriptor cd, int tableNumber) {
Optimizable opt = getOptimizable(tableNumber);
_currentQueryBlock.currentDecoration = createElement(_currentQueryBlock.currentJoinsElement, DECORATION, null);
_currentQueryBlock.currentDecoration.setAttribute(DECORATION_CONGLOM_NAME, cd.getConglomerateName());
_currentQueryBlock.currentDecoration.setAttribute(DECORATION_TABLE_NAME, getOptimizableName(opt).toString());
_currentQueryBlock.currentDecoration.setAttribute(DECORATION_JOIN_STRATEGY, _currentQueryBlock.currentDecorationStrategy.getName());
String[] columnNames = cd.getColumnNames();
if (cd.isIndex() && (columnNames != null)) {
int[] keyColumns = cd.getIndexDescriptor().baseColumnPositions();
for (int i = 0; i < keyColumns.length; i++) {
createElement(_currentQueryBlock.currentDecoration, DECORATION_KEY, columnNames[keyColumns[i] - 1]);
}
}
}
use of org.apache.derby.iapi.sql.compile.Optimizable in project derby by apache.
the class XMLOptTrace method traceStartQueryBlock.
public void traceStartQueryBlock(long timeOptimizationStarted, int optimizerID, OptimizableList optimizableList) {
_maxQueryID++;
if (_currentQueryBlock != null) {
_queryBlockStack.push(_currentQueryBlock);
}
Element queryElement = createElement(_currentStatement, QBLOCK, null);
queryElement.setAttribute(QBLOCK_OPTIMIZER_ID, Integer.toString(optimizerID));
queryElement.setAttribute(QBLOCK_START_TIME, formatTimestamp(timeOptimizationStarted));
queryElement.setAttribute(QBLOCK_ID, Integer.toString(_maxQueryID));
_currentQueryBlock = new QueryBlock(_maxQueryID, optimizableList, queryElement);
if (optimizableList != null) {
for (int i = 0; i < optimizableList.size(); i++) {
Optimizable opt = optimizableList.getOptimizable(i);
if (_cm == null) {
_cm = ((QueryTreeNode) opt).getContextManager();
_lcc = (LanguageConnectionContext) _cm.getContext(LanguageConnectionContext.CONTEXT_ID);
}
Element optElement = createElement(queryElement, QBLOCK_OPTIMIZABLE, getOptimizableName(opt).getFullSQLName());
optElement.setAttribute(QBLOCK_OPT_TABLE_NUMBER, Integer.toString(opt.getTableNumber()));
}
}
}
use of org.apache.derby.iapi.sql.compile.Optimizable in project derby by apache.
the class ProjectRestrictNode method optimizeIt.
/**
* @see Optimizable#optimizeIt
*
* @exception StandardException Thrown on error
*/
@Override
public CostEstimate optimizeIt(Optimizer optimizer, OptimizablePredicateList predList, CostEstimate outerCost, RowOrdering rowOrdering) throws StandardException {
/*
** RESOLVE: Most types of Optimizables only implement estimateCost(),
** and leave it up to optimizeIt() in FromTable to figure out the
** total cost of the join. A ProjectRestrict can have a non-Optimizable
** child, though, in which case we want to tell the child the
** number of outer rows - it could affect the join strategy
** significantly. So we implement optimizeIt() here, which overrides
** the optimizeIt() in FromTable. This assumes that the join strategy
** for which this join node is the inner table is a nested loop join,
** which will not be a valid assumption when we implement other
** strategies like materialization (hash join can work only on
** base tables). The join strategy for a base table under a
** ProjectRestrict is set in the base table itself.
*/
CostEstimate childCost;
setCostEstimate(getCostEstimate(optimizer));
/*
** Don't re-optimize a child result set that has already been fully
** optimized. For example, if the child result set is a SelectNode,
** it will be changed to a ProjectRestrictNode, which we don't want
** to re-optimized.
*/
// NOTE: TO GET THE RIGHT COST, THE CHILD RESULT MAY HAVE TO BE
// OPTIMIZED MORE THAN ONCE, BECAUSE THE NUMBER OF OUTER ROWS
// MAY BE DIFFERENT EACH TIME.
// if (childResultOptimized)
// return costEstimate;
// It's possible that a call to optimize the left/right will cause
// a new "truly the best" plan to be stored in the underlying base
// tables. If that happens and then we decide to skip that plan
// (which we might do if the call to "considerCost()" below decides
// the current path is infeasible or not the best) we need to be
// able to revert back to the "truly the best" plans that we had
// saved before we got here. So with this next call we save the
// current plans using "this" node as the key. If needed, we'll
// then make the call to revert the plans in OptimizerImpl's
// getNextDecoratedPermutation() method.
updateBestPlanMap(ADD_PLAN, this);
/* If the childResult is instanceof Optimizable, then we optimizeIt.
* Otherwise, we are going into a new query block. If the new query
* block has already had its access path modified, then there is
* nothing to do. Otherwise, we must begin the optimization process
* anew on the new query block.
*/
if (childResult instanceof Optimizable) {
childCost = ((Optimizable) childResult).optimizeIt(optimizer, restrictionList, outerCost, rowOrdering);
/* Copy child cost to this node's cost */
getCostEstimate().setCost(childCost.getEstimatedCost(), childCost.rowCount(), childCost.singleScanRowCount());
// Note: we don't call "optimizer.considerCost()" here because
// a) the child will make that call as part of its own
// "optimizeIt()" work above, and b) the child might have
// different criteria for "considering" (i.e. rejecting or
// accepting) a plan's cost than this ProjectRestrictNode does--
// and we don't want to override the child's decision. So as
// with most operations in this class, if the child is an
// Optimizable, we just let it do its own work and make its
// own decisions.
} else if (!accessPathModified) {
if (SanityManager.DEBUG) {
if (!((childResult instanceof SelectNode) || (childResult instanceof RowResultSetNode))) {
SanityManager.THROWASSERT("childResult is expected to be instanceof " + "SelectNode or RowResultSetNode - it is a " + childResult.getClass().getName());
}
}
childResult = childResult.optimize(optimizer.getDataDictionary(), restrictionList, outerCost.rowCount());
/* Copy child cost to this node's cost */
childCost = childResult.getCostEstimate();
getCostEstimate().setCost(childCost.getEstimatedCost(), childCost.rowCount(), childCost.singleScanRowCount());
/* Note: Prior to the fix for DERBY-781 we had calls here
* to set the cost estimate for BestAccessPath and
* BestSortAvoidancePath to equal costEstimate. That used
* to be okay because prior to DERBY-781 we would only
* get here once (per join order) for a given SelectNode/
* RowResultSetNode and thus we could safely say that the
* costEstimate from the most recent call to "optimize()"
* was the best one so far (because we knew that we would
* only call childResult.optimize() once). Now that we
* support hash joins with subqueries, though, we can get
* here twice per join order: once when the optimizer is
* considering a nested loop join with this PRN, and once
* when it is considering a hash join. This means we can't
* just arbitrarily use the cost estimate for the most recent
* "optimize()" as the best cost because that may not
* be accurate--it's possible that the above call to
* childResult.optimize() was for a hash join, but that
* we were here once before (namely for nested loop) and
* the cost of the nested loop is actually less than
* the cost of the hash join. In that case it would
* be wrong to use costEstimate as the cost of the "best"
* paths because it (costEstimate) holds the cost of
* the hash join, not of the nested loop join. So with
* DERBY-781 the following calls were removed:
* getBestAccessPath().setCostEstimate(costEstimate);
* getBestSortAvoidancePath().setCostEstimate(costEstimate);
* If costEstimate *does* actually hold the estimate for
* the best path so far, then we will set BestAccessPath
* and BestSortAvoidancePath as needed in the following
* call to "considerCost".
*/
// childResultOptimized = true;
/* RESOLVE - ARBITRARYHASHJOIN - Passing restriction list here, as above, is correct.
* However, passing predList makes the following work:
* select * from t1, (select * from t2) c properties joinStrategy = hash where t1.c1 = c.c1;
* The following works with restrictionList:
* select * from t1, (select c1 + 0 from t2) c(c1) properties joinStrategy = hash where t1.c1 = c.c1;
*/
optimizer.considerCost(this, restrictionList, getCostEstimate(), outerCost);
}
return getCostEstimate();
}
use of org.apache.derby.iapi.sql.compile.Optimizable in project derby by apache.
the class UnionNode method modifyAccessPath.
/**
* @see Optimizable#modifyAccessPath
*
* @exception StandardException Thrown on error
*/
@Override
public Optimizable modifyAccessPath(JBitSet outerTables) throws StandardException {
Optimizable retOptimizable;
retOptimizable = super.modifyAccessPath(outerTables);
/* We only want call addNewNodes() once */
if (addNewNodesCalled) {
return retOptimizable;
}
return (Optimizable) addNewNodes();
}
use of org.apache.derby.iapi.sql.compile.Optimizable 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;
}
Aggregations