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

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


    ** 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 */
        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;
            }
          }

          /* No need to check the dependencies if the optimizable
           * is already in the join order--because we should have
           * checked its dependencies before putting it there.
           */
          if (found)
          {
            if (SanityManager.DEBUG)
            {
              // Doesn't hurt to check in SANE mode, though...
              if ((nextOptimizable < numOptimizables) &&
                !joinOrderMeetsDependencies(nextOptimizable))
              {
                SanityManager.THROWASSERT(
                  "Found optimizable '" + nextOptimizable +
                  "' in current join order even though " +
                  "its dependencies were NOT satisfied.");
              }
            }

            continue;
          }

          /* Check to make sure that all of the next optimizable's
           * dependencies have been satisfied.
           */
          if ((nextOptimizable < numOptimizables) &&
            !joinOrderMeetsDependencies(nextOptimizable))
          {
            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;
          }

          break;
        }
      }

      /* 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--;

        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);

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

      Optimizable nextOpt =
              optimizableList.getOptimizable(nextOptimizable);

      /* Update the assigned table map to include the newly-placed
       * Optimizable in the current join order.  Assumption is that
       * this OR can always be undone using an XOR, which will only
       * be true if none of the Optimizables have overlapping table
       * maps.  The XOR itself occurs as part of optimizable "PULL"
       * processing.
       */
      if (SanityManager.DEBUG)
      {
        JBitSet optMap =
          (JBitSet)nextOpt.getReferencedTableMap().clone();

        optMap.and(assignedTableMap);
        if (optMap.getFirstSetBit() != -1)
        {
          SanityManager.THROWASSERT(
            "Found multiple optimizables that share one or " +
            "more referenced table numbers (esp: '" +
            optMap + "'), but that should not be the case.");
        }
      }

      assignedTableMap.or(nextOpt.getReferencedTableMap());
      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

   * map representing the current join order.
   */
  private boolean joinOrderMeetsDependencies(int optNumber)
    throws StandardException
  {
    Optimizable nextOpt = optimizableList.getOptimizable(optNumber);
    return nextOpt.legalJoinOrder(assignedTableMap);
  }
View Full Code Here

   * state accordingly.
   */
  private void pullOptimizableFromJoinOrder()
    throws StandardException
  {
    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--but that should ONLY happen if the
      ** optimizable we just pulled was at position 0.  If we
      ** have a newCost that is <= 0 at any other time, then
      ** it's the result of a different kind of precision loss--
      ** namely, the estimated cost of pullMe was so large that
      ** we lost the precision of the accumulated cost as it
      ** existed prior to pullMe. Then when we subtracted
      ** pullMe's cost out, we ended up setting newCost to zero.
      ** That's an unfortunate side effect of optimizer cost
      ** estimates that grow too large. If that's what happened
      ** here,try to make some sense of things by adding up costs
      ** as they existed prior to pullMe...
      */
      if (newCost <= 0.0)
      {
        if (joinPosition == 0)
          newCost = 0.0;
        else
          newCost = recoverCostFromProposedJoinOrder(false);
      }
    }

    /* 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();
        }

        // See discussion above for "newCost"; same applies here.
        if (prevEstimatedCost <= 0.0)
        {
          if (joinPosition == 0)
            prevEstimatedCost = 0.0;
          else
          {
            prevEstimatedCost =
              recoverCostFromProposedJoinOrder(true);
          }
        }

        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.  The reason is that
    ** we could be pulling the Optimizable for the last time
    ** (before returning false), in which case we want it (the
    ** Optimizable) to be holding the best access path that it
    ** had at the time we found bestJoinOrder.  This ensures
    ** that the access path which is generated and executed for
    ** the Optimizable matches the the access path decisions
    ** made by this OptimizerImpl for the best join order.
    **
    ** 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;

    /* If we didn't advance the join position then the optimizable
     * which currently sits at proposedJoinOrder[joinPosition]--call
     * it PULL_ME--is *not* going to remain there. Instead, we're
     * going to pull that optimizable from its position and attempt
     * to put another one in its place.  That said, when we try to
     * figure out which of the other optimizables to place at
     * joinPosition, we'll first do some "dependency checking", the
     * result of which relies on the contents of assignedTableMap.
     * Since assignedTableMap currently holds info about PULL_ME
     * and since PULL_ME is *not* going to remain in the join order,
     * we need to remove the info for PULL_ME from assignedTableMap.
     * Otherwise an Optimizable which depends on PULL_ME could
     * incorrectly be placed in the join order *before* PULL_ME,
     * which would violate the dependency and lead to incorrect
     * results. DERBY-3288.
     */
    assignedTableMap.xor(pullMe.getReferencedTableMap());
  }
 
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, optimizableList) ==
                RequiredRowOrdering.NOTHING_REQUIRED)
          {
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

    JBitSet outerTables = new JBitSet(numOptimizables);

    /* Modify the access path of each table, as necessary */
    for (int ictr = 0; ictr < numOptimizables; ictr++)
    {
      Optimizable optimizable = optimizableList.getOptimizable(ictr);

      /* Current table is treated as an outer table */
      outerTables.or(optimizable.getReferencedTableMap());

      /*
      ** Push any appropriate predicates from this optimizer's list
      ** to the optimizable, as appropriate.
      */
      pushPredicates(optimizable, outerTables);

      optimizableList.setOptimizable(
        ictr,
        optimizable.modifyAccessPath(outerTables));
    }
  }
View Full Code Here

    if (predList != null)
    {

      for (int i = joinPosition - 1; i >= 0; i--)
      {
        Optimizable opt = optimizableList.getOptimizable(
                            proposedJoinOrder[i]);
        double uniqueKeysThisOptimizable = opt.uniqueJoin(predList);
        if (uniqueKeysThisOptimizable > 0.0)
          numUniqueKeys *= opt.uniqueJoin(predList);
      }
    }

    if (numUniqueKeys != 1.0)
    {
View Full Code Here

   *
   * @exception StandardException    Thrown on error
   */
  public Optimizable modifyAccessPath(JBitSet outerTables) throws StandardException
  {
    Optimizable retOptimizable;
    retOptimizable = super.modifyAccessPath(outerTables);

    /* We only want call addNewNodes() once */
    if (addNewNodesCalled)
    {
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.