Package org.apache.derby.iapi.sql.compile

Examples of org.apache.derby.iapi.sql.compile.Optimizable


     * because a predicate's referencedTableMap references the table number
     * of the ProjectRestrictiveNode.  And we need this info to see if
     * a predicate is in storeRestrictionList that can be pushed down.
     * Beetle 3458.
     */
    Optimizable hashTableFor = innerTable;
    if (innerTable instanceof ProjectRestrictNode)
    {
      ProjectRestrictNode prn = (ProjectRestrictNode) innerTable;
      if (prn.getChildResult() instanceof Optimizable)
        hashTableFor = (Optimizable) (prn.getChildResult());
View Full Code Here


  {
    int i;

    for (i = vec.size() - 1; i >= 0; i--)
    {
      Optimizable optTable =
              (Optimizable) vec.elementAt(i);

      if (optTable.hasTableNumber())
      {
        if (optTable.getTableNumber() == tableNumber)
        {
          return true;
        }
      }
    }
View Full Code Here

  {
    int i;

    for (i = vec.size() - 1; i >= 0; i--)
    {
      Optimizable optTable =
              (Optimizable) vec.elementAt(i);

      if (optTable.hasTableNumber())
      {
        if (optTable.getTableNumber() == tableNumber)
        {
          vec.removeElementAt(i);
        }
      }
    }
View Full Code Here

      retval = "Unordered optimizables: ";

      for (i = 0; i < unorderedOptimizables.size(); i++)
      {
        Optimizable opt = (Optimizable) unorderedOptimizables.elementAt(i);
        if (opt.getBaseTableName() != null)
        {
          retval += opt.getBaseTableName();
        }
        else
        {
          retval += unorderedOptimizables.elementAt(i).toString();
        }
        retval += " ";
      }
      retval += "\n";

      retval += "\nAlways ordered optimizables: ";

      for (i = 0; i < alwaysOrderedOptimizables.size(); i++)
      {
        Optimizable opt = (Optimizable) alwaysOrderedOptimizables.elementAt(i);
        if (opt.getBaseTableName() != null)
        {
          retval += opt.getBaseTableName();
        }
        else
        {
          retval += alwaysOrderedOptimizables.elementAt(i).toString();
        }
View Full Code Here

   */
  private boolean unorderedOptimizablesOtherThan(Optimizable optimizable)
  {
    for (int i = 0; i < unorderedOptimizables.size(); i++)
    {
      Optimizable thisOpt =
        (Optimizable) unorderedOptimizables.elementAt(i);

      if (thisOpt != optimizable)
        return true;
    }
View Full Code Here

    ** is presumed to be correlated.
    */
    nonCorrelatedTableMap = new JBitSet(numTablesInQuery);
    for (int tabCtr = 0; tabCtr < numOptimizables; tabCtr++)
    {
      Optimizable  curTable = optimizableList.getOptimizable(tabCtr);
      nonCorrelatedTableMap.or(curTable.getReferencedTableMap());
    }

    /* Get the time that optimization starts */
    timeOptimizationStarted = System.currentTimeMillis();
    reloadBestPlan = false;
View Full Code Here

        int idealOptimizable = firstLookOrder[joinPosition];
        nextOptimizable = idealOptimizable;
        int lookPos = numOptimizables;
        int lastSwappedOpt = -1;

        Optimizable nextOpt;
        for (nextOpt = optimizableList.getOptimizable(nextOptimizable);
          !(nextOpt.legalJoinOrder(assignedTableMap));
          nextOpt = optimizableList.getOptimizable(nextOptimizable))
        {
          // Undo last swap, if we had one.
          if (lastSwappedOpt >= 0) {
            firstLookOrder[joinPosition] = idealOptimizable;
            firstLookOrder[lookPos] = lastSwappedOpt;
          }

          if (lookPos > joinPosition + 1) {
          // we still have other possibilities; get the next
          // one by "swapping" it into the current position.
            lastSwappedOpt = firstLookOrder[--lookPos];
            firstLookOrder[joinPosition] = lastSwappedOpt;
            firstLookOrder[lookPos] = idealOptimizable;
            nextOptimizable = lastSwappedOpt;
          }
          else {
          // we went through all of the available optimizables
          // and none of them were legal in the current position;
          // so we give up and fall back to normal processing.
          // Note: we have to make sure we reload the best plans
          // as we rewind since they may have been clobbered
          // (as part of the current join order) before we got
          // here.
            if (joinPosition > 0) {
              joinPosition--;
              reloadBestPlan = true;
              rewindJoinOrder();
            }
            permuteState = NO_JUMP;
            break;
          }
        }

        if (permuteState == NO_JUMP)
          continue;

        if (joinPosition == numOptimizables - 1) {
        // we just set the final position within our
        // "firstLookOrder" join order; now go ahead
        // and search for the best join order, starting from
        // the join order stored in "firstLookOrder".  This
        // is called walking "high" because we're searching
        // the join orders that are at or "above" (after) the
        // order found in firstLookOrder.  Ex. if we had three
        // optimizables and firstLookOrder was [1 2 0], then
        // the "high" would be [1 2 0], [2 0 1] and [2 1 0];
        // the "low" would be [0 1 2], [0 2 1], and [1 0 2].
        // We walk the "high" first, then fall back and
        // walk the "low".
          permuteState = WALK_HIGH;
        }
      }
      else
      {
        /* Find the next unused table at this join position */
        nextOptimizable = proposedJoinOrder[joinPosition] + 1;

        for ( ; nextOptimizable < numOptimizables; nextOptimizable++)
        {
          boolean found = false;
          for (int posn = 0; posn < joinPosition; posn++)
          {
            /*
            ** Is this optimizable already somewhere
            ** in the join order?
            */
            if (proposedJoinOrder[posn] == nextOptimizable)
            {
              found = true;
              break;
            }
          }

          /* Check to make sure that all of the next optimizable's
           * dependencies have been satisfied.
           */
          if (nextOptimizable < numOptimizables)
          {
            Optimizable nextOpt =
                optimizableList.getOptimizable(nextOptimizable);
            if (! (nextOpt.legalJoinOrder(assignedTableMap)))
            {
              if (optimizerTrace)
              {
                trace(SKIPPING_JOIN_ORDER, nextOptimizable, 0, 0.0, null);
              }

              /*
              ** If this is a user specified join order then it is illegal.
              */
              if ( ! optimizableList.optimizeJoinOrder())
              {
                if (optimizerTrace)
                {
                  trace(ILLEGAL_USER_JOIN_ORDER, 0, 0, 0.0, null);
                }

                throw StandardException.newException(SQLState.LANG_ILLEGAL_FORCED_JOIN_ORDER);
              }
              continue;
            }
          }

          if (! found)
          {
            break;
          }
        }

      }

      /*
      ** We are going to try an optimizable at the current join order
      ** position.  Is there one already at that position?
      */
      if (proposedJoinOrder[joinPosition] >= 0)
      {
        /*
        ** We are either going to try another table at the current
        ** join order position, or we have exhausted all the tables
        ** at the current join order position.  In either case, we
        ** need to pull the table at the current join order position
        ** and remove it from the join order.
        */
        Optimizable pullMe =
          optimizableList.getOptimizable(
                      proposedJoinOrder[joinPosition]);

        /*
        ** Subtract the cost estimate of the optimizable being
        ** removed from the total 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.
        */
        double prevRowCount;
        double prevSingleScanRowCount;
        int prevPosition = 0;
        if (joinPosition == 0)
        {
          prevRowCount = outermostCostEstimate.rowCount();
          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;
            for (int i = 0; i < numOptimizables; i++//simple selection sort
            {
              int k = i;
              for (int j = i+1; j < numOptimizables; j++)
                if (rc[j] < rc[k])  k = j;
              if (k != i)
              {
                rc[k] = rc[i]//destroy the bridge
                temp = firstLookOrder[i];
                firstLookOrder[i] = firstLookOrder[k];
                firstLookOrder[k] = temp;
                doIt = true;
              }
            }

            if (doIt)
            {
              joinPosition--;
              rewindJoinOrder()//jump from ground
              continue;
            }
            else permuteState = NO_JUMP;  //never
          }
        }

        /*
        ** We have exhausted all the optimizables at this level.
        ** Go back up one level.
        */

        /* Go back up one join position */
        joinPosition--;

        /* Clear the assigned table map for the previous position
         * NOTE: We need to do this here to for the dependency tracking
         */
        if (joinPosition >= 0)
        {
          Optimizable pullMe =
            optimizableList.getOptimizable(
                      proposedJoinOrder[joinPosition]);

          /*
          ** Clear the bits from the table at this join position.
          ** This depends on them having been set previously.
          ** NOTE: We need to do this here to for the dependency tracking
          */
          assignedTableMap.xor(pullMe.getReferencedTableMap());
        }

        if (joinPosition < 0 && permuteState == WALK_HIGH) //reached peak
        {
          joinPosition = 0//reset, fall down the hill
          permuteState = WALK_LOW;
        }
        continue;
      }

      /*
      ** We have found another optimizable to try at this join position.
      */
      proposedJoinOrder[joinPosition] = nextOptimizable;

      if (permuteState == WALK_LOW)
      {
        boolean finishedCycle = true;
        for (int i = 0; i < numOptimizables; i++)
        {
          if (proposedJoinOrder[i] < firstLookOrder[i])
          {
            finishedCycle = false;
            break;
          }
          else if (proposedJoinOrder[i] > firstLookOrder[i])  //done
            break;
        }
        if (finishedCycle)
        {
          // We just set proposedJoinOrder[joinPosition] above, so
          // if we're done we need to put it back to -1 to indicate
          // that it's an empty slot.  Then we rewind and pull any
          // other Optimizables at positions < joinPosition.
          // Note: we have to make sure we reload the best plans
          // as we rewind since they may have been clobbered
          // (as part of the current join order) before we got
          // here.
          proposedJoinOrder[joinPosition] = -1;
          joinPosition--;
          if (joinPosition >= 0)
          {
            reloadBestPlan = true;
            rewindJoinOrder();
            joinPosition = -1;
          }

          permuteState = READY_TO_JUMP;
          endOfRoundCleanup();
          return false;
        }
      }

      /* Re-init (clear out) the cost for the best access path
       * when placing a table.
       */
      optimizableList.getOptimizable(nextOptimizable).
        getBestAccessPath().setCostEstimate((CostEstimate) null);

      /* Set the assigned table map to be exactly the tables
       * in the current join order.
       */
      assignedTableMap.clearAll();
      for (int index = 0; index <= joinPosition; index++)
      {
        assignedTableMap.or(optimizableList.getOptimizable(proposedJoinOrder[index]).getReferencedTableMap());
      }

      if (optimizerTrace)
      {
        trace(CONSIDERING_JOIN_ORDER, 0, 0, 0.0, null);
      }

      Optimizable nextOpt =
              optimizableList.getOptimizable(nextOptimizable);

      nextOpt.startOptimizing(this, currentRowOrdering);

      pushPredicates(
        optimizableList.getOptimizable(nextOptimizable),
        assignedTableMap);

View Full Code Here

  private void rewindJoinOrder()
    throws StandardException
  {
    for (; ; joinPosition--)
    {
      Optimizable pullMe =
        optimizableList.getOptimizable(
                  proposedJoinOrder[joinPosition]);
      pullMe.pullOptPredicates(predicateList);
      if (reloadBestPlan)
        pullMe.updateBestPlanMap(FromTable.LOAD_PLAN, this);
      proposedJoinOrder[joinPosition] = -1;
      if (joinPosition == 0) break;
    }
    currentCost.setCost(0.0d, 0.0d, 0.0d);
    currentSortAvoidanceCost.setCost(0.0d, 0.0d, 0.0d);
View Full Code Here

   */
  public boolean getNextDecoratedPermutation()
        throws StandardException
  {
    boolean    retval;
    Optimizable curOpt =
      optimizableList.getOptimizable(proposedJoinOrder[joinPosition]);
    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,
                    (OptimizablePredicateList) null,
                    currentRowOrdering);

    // 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.
      if (curOpt.getBestAccessPath().getCostEstimate().compare(
        curOpt.getCurrentAccessPath().getCostEstimate()) != 0)
      {
        curOpt.updateBestPlanMap(FromTable.LOAD_PLAN, curOpt);
      }
      else if (curOpt.getBestAccessPath().getCostEstimate().rowCount() <
        curOpt.getCurrentAccessPath().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.
        curOpt.updateBestPlanMap(FromTable.LOAD_PLAN, curOpt);
      }
    }

    /* 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.
     */
    curOpt.updateBestPlanMap(FromTable.REMOVE_PLAN, curOpt);

    /*
    ** 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
      ** optimizable.
      */
      currentCost.setCost(
        currentCost.getEstimatedCost() + ce.getEstimatedCost(),
        ce.rowCount(),
        ce.singleScanRowCount());

      if (curOpt.considerSortAvoidancePath() &&
        requiredRowOrdering != null)
      {
        /* Add the cost for the sort avoidance path, if there is one */
        ce = curOpt.getBestSortAvoidancePath().getCostEstimate();

        currentSortAvoidanceCost.setCost(
          currentSortAvoidanceCost.getEstimatedCost() +
            ce.getEstimatedCost(),
          ce.rowCount(),
          ce.singleScanRowCount());
      }

      if (optimizerTrace)
      {
        trace(TOTAL_COST_NON_SA_PLAN, 0, 0, 0.0, null);
        if (curOpt.considerSortAvoidancePath())
        {
          trace(TOTAL_COST_SA_PLAN, 0, 0, 0.0, null);
        }
      }
       
      /* Do we have a complete join order? */
      if ( joinPosition == (numOptimizables - 1) )
      {
        if (optimizerTrace)
        {
          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
              requiredRowOrdering.estimateCost(
                          bestCost.rowCount(),
                          bestRowOrdering,
                          sortCost
                          );
              double oldSortCost = sortCost.getEstimatedCost();
              requiredRowOrdering.estimateCost(
                          currentCost.rowCount(),
                          bestRowOrdering,
                          sortCost
                          );
              gotSortCost = true;
              bestCost.setCost(bestCost.getEstimatedCost() -
                      oldSortCost +
                      sortCost.getEstimatedCost(),
                      sortCost.rowCount(),
                      currentCost.singleScanRowCount());
            }
            else if (bestCost.rowCount() < currentCost.rowCount())
            {
              // adjust currentCost's rowCount
              currentCost.setCost(currentCost.getEstimatedCost(),
                        bestCost.rowCount(),
                        currentCost.singleScanRowCount());
            }
          }

          /* 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)
          {
            requiredRowOrdering.estimateCost(
                          currentCost.rowCount(),
                          bestRowOrdering,
                          sortCost
                          );
          }

          originalRowCount = currentCost.rowCount();

          currentCost.setCost(currentCost.getEstimatedCost() +
                    sortCost.getEstimatedCost(),
                    sortCost.rowCount(),
                    currentCost.singleScanRowCount()
                    );
         
          if (optimizerTrace)
          {
            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) ||
          bestCost.isUninitialized())
        {
          rememberBestCost(currentCost, Optimizer.NORMAL_PLAN);

          // Since we just remembered all of the best plans,
          // no need to reload them when pulling Optimizables
          // from this join order.
          reloadBestPlan = false;
        }
        else
          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() -
                    sortCost.getEstimatedCost();
          if (newCost < 0.0)
            newCost = 0.0;
         
          currentCost.setCost(newCost,
                    originalRowCount,
                    currentCost.singleScanRowCount()
                    );
        }

        /*
        ** 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 &&
          curOpt.considerSortAvoidancePath())
        {
          if (requiredRowOrdering.sortRequired(bestRowOrdering) ==
                  RequiredRowOrdering.NOTHING_REQUIRED)
          {
            if (optimizerTrace)
View Full Code Here

    {
      SanityManager.ASSERT(outerCost != null,
        "outerCost is not expected to be null");
    }

    Optimizable optimizable = optimizableList.getOptimizable(proposedJoinOrder[joinPosition]);

    /*
    ** Don't consider non-feasible join strategies.
    */
    if ( ! optimizable.feasibleJoinStrategy(predicateList, this))
    {
      return;
    }

    /* Cost the optimizable at the current join position */
    optimizable.optimizeIt(this,
                 predicateList,
                 outerCost,
                 currentRowOrdering);
  }
View Full Code Here

TOP

Related Classes of org.apache.derby.iapi.sql.compile.Optimizable

Copyright © 2018 www.massapicom. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.