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

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


    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

   *
   * @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

   *
   * @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

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

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.