prevSingleScanRowCount = outermostCostEstimate.singleScanRowCount();
}
else
{
prevPosition = proposedJoinOrder[joinPosition - 1];
CostEstimate localCE =
optimizableList.
getOptimizable(prevPosition).
getBestAccessPath().
getCostEstimate();
prevRowCount = localCE.rowCount();
prevSingleScanRowCount = localCE.singleScanRowCount();
}
/*
** If there is no feasible join order, the cost estimate
** in the best access path may never have been set.
** In this case, do not subtract anything from the
** current cost, since nothing was added to the current
** cost.
*/
double newCost = currentCost.getEstimatedCost();
double pullCost = 0.0;
CostEstimate pullCostEstimate =
pullMe.getBestAccessPath().getCostEstimate();
if (pullCostEstimate != null)
{
pullCost = pullCostEstimate.getEstimatedCost();
newCost -= pullCost;
/*
** It's possible for newCost to go negative here due to
** loss of precision.
*/
if (newCost < 0.0)
newCost = 0.0;
}
/* If we are choosing a new outer table, then
* we rest the starting cost to the outermostCost.
* (Thus avoiding any problems with floating point
* accuracy and going negative.)
*/
if (joinPosition == 0)
{
if (outermostCostEstimate != null)
{
newCost = outermostCostEstimate.getEstimatedCost();
}
else
{
newCost = 0.0;
}
}
currentCost.setCost(
newCost,
prevRowCount,
prevSingleScanRowCount);
/*
** Subtract from the sort avoidance cost if there is a
** required row ordering.
**
** NOTE: It is not necessary here to check whether the
** best cost was ever set for the sort avoidance path,
** because it considerSortAvoidancePath() would not be
** set if there cost were not set.
*/
if (requiredRowOrdering != null)
{
if (pullMe.considerSortAvoidancePath())
{
AccessPath ap = pullMe.getBestSortAvoidancePath();
double prevEstimatedCost = 0.0d;
/*
** Subtract the sort avoidance cost estimate of the
** optimizable being removed from the total sort
** avoidance cost estimate.
**
** 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 optimizable.
*/
if (joinPosition == 0)
{
prevRowCount = outermostCostEstimate.rowCount();
prevSingleScanRowCount = outermostCostEstimate.singleScanRowCount();
/* If we are choosing a new outer table, then
* we rest the starting cost to the outermostCost.
* (Thus avoiding any problems with floating point
* accuracy and going negative.)
*/
prevEstimatedCost = outermostCostEstimate.getEstimatedCost();
}
else
{
CostEstimate localCE =
optimizableList.
getOptimizable(prevPosition).
getBestSortAvoidancePath().
getCostEstimate();
prevRowCount = localCE.rowCount();
prevSingleScanRowCount = localCE.singleScanRowCount();
prevEstimatedCost = currentSortAvoidanceCost.getEstimatedCost() -
ap.getCostEstimate().getEstimatedCost();
}
currentSortAvoidanceCost.setCost(
prevEstimatedCost,
prevRowCount,
prevSingleScanRowCount);
/*
** Remove the table from the best row ordering.
** It should not be necessary to remove it from
** the current row ordering, because it is
** maintained as we step through the access paths
** for the current Optimizable.
*/
bestRowOrdering.removeOptimizable(
pullMe.getTableNumber());
/*
** When removing a table from the join order,
** the best row ordering for the remaining outer tables
** becomes the starting point for the row ordering of
** the current table.
*/
bestRowOrdering.copy(currentRowOrdering);
}
}
/*
** Pull the predicates at from the optimizable and put
** them back in the predicate list.
**
** NOTE: This is a little inefficient because it pulls the
** single-table predicates, which are guaranteed to always
** be pushed to the same optimizable. We could make this
** leave the single-table predicates where they are.
*/
pullMe.pullOptPredicates(predicateList);
/*
** When we pull an Optimizable we need to go through and
** load whatever best path we found for that Optimizable
** with respect to _this_ OptimizerImpl. An Optimizable
** can have different "best paths" for different Optimizer
** Impls if there are subqueries beneath it; we need to make
** sure that when we pull it, it's holding the best path as
** as we determined it to be for _us_.
**
** NOTE: We we only reload the best plan if it's necessary
** to do so--i.e. if the best plans aren't already loaded.
** The plans will already be loaded if the last complete
** join order we had was the best one so far, because that
** means we called "rememberAsBest" on every Optimizable
** in the list and, as part of that call, we will run through
** and set trulyTheBestAccessPath for the entire subtree.
** So if we haven't tried any other plans since then,
** we know that every Optimizable (and its subtree) already
** has the correct best plan loaded in its trulyTheBest
** path field. It's good to skip the load in this case
** because 'reloading best plans' involves walking the
** entire subtree of _every_ Optimizable in the list, which
** can be expensive if there are deeply nested subqueries.
*/
if (reloadBestPlan)
pullMe.updateBestPlanMap(FromTable.LOAD_PLAN, this);
/* Mark current join position as unused */
proposedJoinOrder[joinPosition] = -1;
}
/* Have we exhausted all the optimizables at this join position? */
if (nextOptimizable >= numOptimizables)
{
/*
** If we're not optimizing the join order, remember the first
** join order.
*/
if ( ! optimizableList.optimizeJoinOrder())
{
// Verify that the user specified a legal join order
if ( ! optimizableList.legalJoinOrder(numTablesInQuery))
{
if (optimizerTrace)
{
trace(ILLEGAL_USER_JOIN_ORDER, 0, 0, 0.0, null);
}
throw StandardException.newException(SQLState.LANG_ILLEGAL_FORCED_JOIN_ORDER);
}
if (optimizerTrace)
{
trace(USER_JOIN_ORDER_OPTIMIZED, 0, 0, 0.0, null);
}
desiredJoinOrderFound = true;
}
if (permuteState == READY_TO_JUMP && joinPosition > 0 && joinPosition == numOptimizables-1)
{
permuteState = JUMPING;
/* A simple heuristics is that the row count we got indicates a potentially
* good join order. We'd like row count to get big as late as possible, so
* that less load is carried over.
*/
double rc[] = new double[numOptimizables];
for (int i = 0; i < numOptimizables; i++)
{
firstLookOrder[i] = i;
CostEstimate ce = optimizableList.getOptimizable(i).
getBestAccessPath().getCostEstimate();
if (ce == null)
{
permuteState = READY_TO_JUMP; //come again?
break;
}
rc[i] = ce.singleScanRowCount();
}
if (permuteState == JUMPING)
{
boolean doIt = false;
int temp;