public boolean getNextDecoratedPermutation()
Optimizable curOpt =
double originalRowCount = 0.0;
// RESOLVE: Should we step through the different join strategies here?
/* Returns true until all access paths are exhausted */
retval = curOpt.nextAccessPath(this,
// If the previous path that we considered for curOpt was _not_ the best
// path for this round, then we need to revert back to whatever the
// best plan for curOpt was this round. Note that the cost estimate
// for bestAccessPath could be null here if the last path that we
// checked was the only one possible for this round.
if ((curOpt.getBestAccessPath().getCostEstimate() != null) &&
(curOpt.getCurrentAccessPath().getCostEstimate() != null))
// Note: we can't just check to see if bestCost is cheaper
// than currentCost because it's possible that currentCost
// is actually cheaper--but it may have been 'rejected' because
// it would have required too much memory. So we just check
// to see if bestCost and currentCost are different. If so
// then we know that the most recent access path (represented
// by "current" access path) was not the best.
curOpt.getCurrentAccessPath().getCostEstimate()) != 0)
else if (curOpt.getBestAccessPath().getCostEstimate().rowCount() <
// If currentCost and bestCost have the same cost estimate
// but currentCost has been rejected because of memory, we
// still need to revert the plans. In this case the row
// count for currentCost will be greater than the row count
// for bestCost, so that's what we just checked.
/* If we needed to revert plans for curOpt, we just did it above.
* So we no longer need to keep the previous best plan--and in fact,
* keeping it can lead to extreme memory usage for very large
* queries. So delete the stored plan for curOpt. DERBY-1315.
** When all the access paths have been looked at, we know what the
** cheapest one is, so remember it. Only do this if a cost estimate
** has been set for the best access path - one will not have been
** set if no feasible plan has been found.
CostEstimate ce = curOpt.getBestAccessPath().getCostEstimate();
if ( ( ! retval ) && (ce != null))
** Add the cost of the current optimizable to the total cost.
** The total cost is the sum of all the costs, but the total
** number of rows is the number of rows returned by the innermost
currentCost.getEstimatedCost() + ce.getEstimatedCost(),
if (curOpt.considerSortAvoidancePath() &&
requiredRowOrdering != null)
/* Add the cost for the sort avoidance path, if there is one */
ce = curOpt.getBestSortAvoidancePath().getCostEstimate();
trace(TOTAL_COST_NON_SA_PLAN, 0, 0, 0.0, null);
trace(TOTAL_COST_SA_PLAN, 0, 0, 0.0, null);
/* Do we have a complete join order? */
if ( joinPosition == (numOptimizables - 1) )
trace(COMPLETE_JOIN_ORDER, 0, 0, 0.0, null);
/* Add cost of sorting to non-sort-avoidance cost */
if (requiredRowOrdering != null)
boolean gotSortCost = false;
/* Only get the sort cost once */
if (sortCost == null)
sortCost = newCostEstimate();
/* requiredRowOrdering records if the bestCost so far is
* sort-needed or not, as done in rememberBestCost. If
* the bestCost so far is sort-needed, and assume
* currentCost is also sort-needed, we want this comparison
* to be as accurate as possible. Different plans may
* produce different estimated row count (eg., heap scan
* vs. index scan during a join), sometimes the difference
* could be very big. However the actual row count should
* be only one value. So when comparing these two plans,
* we want them to have the same sort cost. We want to
* take the smaller row count, because a better estimation
* (eg. through index) would yield a smaller number. We
* adjust the bestCost here if it had a bigger rowCount
* estimate. The performance improvement of doing this
* sometimes is quite dramatic, eg. from 17 sec to 0.5 sec,
* see beetle 4353.
else if (requiredRowOrdering.getSortNeeded())
if (bestCost.rowCount() > currentCost.rowCount())
// adjust bestCost
double oldSortCost = sortCost.getEstimatedCost();
gotSortCost = true;
else if (bestCost.rowCount() < currentCost.rowCount())
// adjust currentCost's rowCount
/* This does not figure out if sorting is necessary, just
* an asumption that sort is needed; if the assumption is
* wrong, we'll look at sort-avoidance cost as well, later
if (! gotSortCost)
originalRowCount = currentCost.rowCount();
trace(COST_OF_SORTING, 0, 0, 0.0, null);
trace(TOTAL_COST_WITH_SORTING, 0, 0, 0.0, null);
** Is the cost of this join order lower than the best one we've
** found so far?
** NOTE: If the user has specified a join order, it will be the
** only join order the optimizer considers, so it is OK to use
** costing to decide that it is the "best" join order.
** For very deeply nested queries, it's possible that the optimizer
** will return an estimated cost of Double.INFINITY, which is
** greater than our uninitialized cost of Double.MAX_VALUE and
** thus the "compare" check below will return false. So we have
** to check to see if bestCost is uninitialized and, if so, we
** save currentCost regardless of what value it is--because we
** haven't found anything better yet.
** That said, it's also possible for bestCost to be infinity
** AND for current cost to be infinity, as well. In that case
** we can't really tell much by comparing the two, so for lack
** of better alternative we look at the row counts. See
** CostEstimateImpl.compare() for more.
if ((! foundABestPlan) ||
(currentCost.compare(bestCost) < 0) ||
// Since we just remembered all of the best plans,
// no need to reload them when pulling Optimizables
// from this join order.
reloadBestPlan = false;
reloadBestPlan = true;
/* Subtract cost of sorting from non-sort-avoidance cost */
if (requiredRowOrdering != null)
** The cost could go negative due to loss of precision.
double newCost = currentCost.getEstimatedCost() -
if (newCost < 0.0)
newCost = 0.0;
** This may be the best sort-avoidance plan if there is a
** required row ordering, and we are to consider a sort
** avoidance path on the last Optimizable in the join order.
if (requiredRowOrdering != null &&
bestRowOrdering, optimizableList) ==