Search in sources :

Example 6 with OptimizablePredicateList

use of org.apache.derby.iapi.sql.compile.OptimizablePredicateList in project derby by apache.

the class PredicateList method transferAllPredicates.

/**
 * @see OptimizablePredicateList#transferAllPredicates
 *
 * @exception StandardException		Thrown on error
 */
public void transferAllPredicates(OptimizablePredicateList otherList) throws StandardException {
    PredicateList theOtherList = (PredicateList) otherList;
    for (Predicate predicate : this) {
        /*
			** Clear all of the scan flags since they may be different
			** when the new list is re-classified
			*/
        predicate.clearScanFlags();
        // Add the predicate to the other list
        theOtherList.addPredicate(predicate);
    }
    // Remove all of the predicates from this list
    removeAllElements();
    /*
		** This list is now empty, so there are no start predicates,
	 	** stop predicates, or qualifiers.
		*/
    numberOfStartPredicates = 0;
    numberOfStopPredicates = 0;
    numberOfQualifiers = 0;
}
Also used : OptimizablePredicateList(org.apache.derby.iapi.sql.compile.OptimizablePredicateList) OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate)

Example 7 with OptimizablePredicateList

use of org.apache.derby.iapi.sql.compile.OptimizablePredicateList in project derby by apache.

the class PredicateList method selectivity.

/**
 * @see OptimizablePredicateList#selectivity
 */
public double selectivity(Optimizable optTable) throws StandardException {
    TableDescriptor td = optTable.getTableDescriptor();
    ConglomerateDescriptor[] conglomerates = td.getConglomerateDescriptors();
    int numPredicates = size();
    int numConglomerates = conglomerates.length;
    if (numConglomerates == 1)
        // one conglomerate; must be heap.
        return -1.0d;
    if (numPredicates == 0)
        // no predicates why bother?
        return -1.0d;
    boolean nothingYet = true;
    /* before we start, lets select non-redundant prediates into a working
		 * list; we'll work with the workingPredicates list from now on in this
		 * routine. 
		 */
    PredicateList workingPredicates = new PredicateList(getContextManager());
    for (int i = 0; i < numPredicates; i++) {
        if (isRedundantPredicate(i))
            continue;
        /* to workingPredicates only add useful predicates... */
        workingPredicates.addOptPredicate(elementAt(i));
    }
    int numWorkingPredicates = workingPredicates.size();
    /*--------------------------------------------------------------------
		 * In the first phase, the routine initializes an array of
		 * predicateWrapperLists-- one list for each conglomerate that has
		 * statistics. 
		 *
		 * predsForConglomerates is an array of pwList. For each conglomerate we
		 * keep a pwList of predicates that have an equals predicate on a column
		 * in the conglomerate.
		 *
		 * As an example consider a table T, with indices on
		 * T(c1)-->conglom_one, T(c2,c1)-->conglom_two.
		 *
		 * if we have the following predicates:
		 *  T.c1=T1.x (p1) and T.c1=T2.y (p2) and T.c2=T1.z (p3), then we'll have the 
		 * after the first loop is done, we'll have the following setup.
		 *
		 * conglom_one: pwList [p1,p2]
		 * conglom_two: pwList [p1,p2,p3].
		 *
		 * Note that although p1,p2 appear on both conglomerates, the
		 * indexPosition of p1 and p2 on the first list is 0 (first index
		 * position) while the index position of p1,p2 on the second list is 1
		 * (second index position).
		 *
		 * PredicateWrapper and PredicateWrapperLists are inner classes used
		 * only in this file.
		 * -------------------------------------------------------------------- */
    PredicateWrapperList[] predsForConglomerates = new PredicateWrapperList[numConglomerates];
    for (int i = 0; i < numConglomerates; i++) {
        ConglomerateDescriptor cd = conglomerates[i];
        if (!cd.isIndex())
            continue;
        if (!td.statisticsExist(cd))
            continue;
        int[] baseColumnList = cd.getIndexDescriptor().baseColumnPositions();
        for (int j = 0; j < numWorkingPredicates; j++) {
            Predicate pred = workingPredicates.elementAt(j);
            int ip = pred.hasEqualOnColumnList(baseColumnList, optTable);
            if (ip < 0)
                // look at the next predicate.
                continue;
            nothingYet = false;
            if (predsForConglomerates[i] == null) {
                predsForConglomerates[i] = new PredicateWrapperList(numWorkingPredicates);
            }
            PredicateWrapper newpw = new PredicateWrapper(ip, pred, j);
            predsForConglomerates[i].insert(newpw);
        }
    // for (j = 0;
    }
    if (nothingYet) {
        return -1.0;
    }
    /*------------------------------------------------------------------
		 * In the second phase we,
		 * walk the predsForConglomerateList again-- if we find
		 * a break in the indexPositions we remove the predicates
		 * after the gap. To clarify, if we have equal predicates on the first
		 * and the third index positions, we can throw away the predicate on 
		 * the 3rd index position-- it doesn't do us any good.
		 *-------------------------------------------------------------------*/
    int maxOverlap = -1;
    for (int i = 0; i < numConglomerates; i++) {
        if (predsForConglomerates[i] == null)
            continue;
        predsForConglomerates[i].retainLeadingContiguous();
    }
    // for (i = 0; i < ...)
    calculateWeight(predsForConglomerates, numWorkingPredicates);
    /*-------------------------------------------------------------------
		 * In the third phase we loop through predsForConglomerates choosing the
		 * best fit (chooseLongestMatch) of predicates. we use the statistics
		 * for the set of predicates returned by chooseLongestMatch and then
		 * loop until we can't find any more statistics or we have exhausted all
		 * the predicates for which we are trying to find statistics.
		 *--------------------------------------------------------------------*/
    double selectivity = 1.0;
    ArrayList<Predicate> maxPreds = new ArrayList<Predicate>();
    while (true) {
        maxPreds.clear();
        int conglomIndex = chooseLongestMatch(predsForConglomerates, maxPreds, numWorkingPredicates);
        if (conglomIndex == -1)
            // no more stats available.
            break;
        selectivity *= td.selectivityForConglomerate(conglomerates[conglomIndex], maxPreds.size());
        for (int i = 0; i < maxPreds.size(); i++) {
            /* remove the predicates that we've calculated the selectivity
				 * of, from workingPredicates.
				 */
            Predicate p = maxPreds.get(i);
            workingPredicates.removeOptPredicate(p);
        }
        if (workingPredicates.size() == 0)
            break;
    }
    if (workingPredicates.size() != 0) {
        selectivity *= workingPredicates.selectivityNoStatistics(optTable);
    }
    return selectivity;
}
Also used : ArrayList(java.util.ArrayList) ConglomerateDescriptor(org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor) TableDescriptor(org.apache.derby.iapi.sql.dictionary.TableDescriptor) OptimizablePredicate(org.apache.derby.iapi.sql.compile.OptimizablePredicate) OptimizablePredicateList(org.apache.derby.iapi.sql.compile.OptimizablePredicateList)

Example 8 with OptimizablePredicateList

use of org.apache.derby.iapi.sql.compile.OptimizablePredicateList in project derby by apache.

the class FromBaseTable method isOneRowResultSet.

/**
 * Is this a one-row result set with the given conglomerate descriptor?
 */
private boolean isOneRowResultSet(ConglomerateDescriptor cd, OptimizablePredicateList predList) throws StandardException {
    if (predList == null) {
        return false;
    }
    if (SanityManager.DEBUG) {
        if (!(predList instanceof PredicateList)) {
            SanityManager.THROWASSERT("predList should be a PredicateList, but is a " + predList.getClass().getName());
        }
    }
    PredicateList restrictList = (PredicateList) predList;
    if (!cd.isIndex()) {
        return false;
    }
    IndexRowGenerator irg = cd.getIndexDescriptor();
    // is this a unique index
    if (!irg.isUnique()) {
        return false;
    }
    int[] baseColumnPositions = irg.baseColumnPositions();
    // Do we have an exact match on the full key
    for (int index = 0; index < baseColumnPositions.length; index++) {
        // get the column number at this position
        int curCol = baseColumnPositions[index];
        /* Is there a pushable equality predicate on this key column?
			 * (IS NULL is also acceptable)
			 */
        if (!restrictList.hasOptimizableEqualityPredicate(this, curCol, true)) {
            return false;
        }
    }
    return true;
}
Also used : IndexRowGenerator(org.apache.derby.iapi.sql.dictionary.IndexRowGenerator) OptimizablePredicateList(org.apache.derby.iapi.sql.compile.OptimizablePredicateList)

Example 9 with OptimizablePredicateList

use of org.apache.derby.iapi.sql.compile.OptimizablePredicateList in project derby by apache.

the class OptimizerImpl method getNextDecoratedPermutation.

/**
 * @see Optimizer#getNextDecoratedPermutation
 *
 * @exception StandardException		Thrown on error
 */
public boolean getNextDecoratedPermutation() throws StandardException {
    boolean retval;
    Optimizable curOpt = optimizableList.getOptimizable(proposedJoinOrder[joinPosition]);
    double originalRowCount = 0.0;
    while (true) {
        /* Returns true until all access paths are exhausted */
        retval = curOpt.nextAccessPath(this, (OptimizablePredicateList) null, currentRowOrdering);
        // if the user didn't specify an explicit plan, we're ok
        if (overridingPlan == null) {
            break;
        }
        if (!retval) {
            break;
        }
        // the join order, then we move on to the next position
        if (currentPlan != null) {
            if (currentPlan.countLeafNodes() == (joinPosition + 1)) {
                retval = false;
                break;
            }
        }
        // at this point, figure out if the plan so far is a prefix of the desired plan
        OptimizerPlan candidate = OptimizerPlan.makeRowSource(getTupleDescriptor(curOpt), dDictionary);
        if (candidate == null) {
            retval = false;
            break;
        }
        if (currentPlan != null) {
            candidate = new OptimizerPlan.Join(curOpt.getCurrentAccessPath().getJoinStrategy(), currentPlan, candidate);
        }
        if (candidate.isLeftPrefixOf(overridingPlan)) {
            currentPlan = candidate;
            break;
        }
    // well, that decoration didn't match up with the user-specified plan.
    // try again
    }
    // checked was the only one possible for this round.
    if ((curOpt.getBestAccessPath().getCostEstimate() != null) && (curOpt.getCurrentAccessPath().getCostEstimate() != null)) {
        // 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 (tracingIsOn()) {
            tracer().traceCostWithoutSortAvoidance(currentCost);
            if (curOpt.considerSortAvoidancePath()) {
                tracer().traceCostWithSortAvoidance(currentSortAvoidanceCost);
            }
        }
        /* Do we have a complete join order? */
        if (joinPosition == (numOptimizables - 1)) {
            if (tracingIsOn()) {
                tracer().traceCompleteJoinOrder();
            }
            /* 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();
                } else /* 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.
					 */
                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 (tracingIsOn()) {
                    tracer().traceSortCost(sortCost, currentCost);
                }
            }
            /*
				** 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, proposedJoinOrder) == RequiredRowOrdering.NOTHING_REQUIRED) {
                    if (tracingIsOn()) {
                        tracer().traceCurrentPlanAvoidsSort(bestCost, currentSortAvoidanceCost);
                    }
                    if ((currentSortAvoidanceCost.compare(bestCost) <= 0) || bestCost.isUninitialized()) {
                        rememberBestCost(currentSortAvoidanceCost, Optimizer.SORT_AVOIDANCE_PLAN);
                    }
                }
            }
        }
    }
    return retval;
}
Also used : CostEstimate(org.apache.derby.iapi.sql.compile.CostEstimate) Optimizable(org.apache.derby.iapi.sql.compile.Optimizable) OptimizablePredicateList(org.apache.derby.iapi.sql.compile.OptimizablePredicateList) OptimizerPlan(org.apache.derby.iapi.sql.compile.OptimizerPlan)

Aggregations

OptimizablePredicateList (org.apache.derby.iapi.sql.compile.OptimizablePredicateList)9 OptimizablePredicate (org.apache.derby.iapi.sql.compile.OptimizablePredicate)4 CostEstimate (org.apache.derby.iapi.sql.compile.CostEstimate)3 AccessPath (org.apache.derby.iapi.sql.compile.AccessPath)2 IndexRowGenerator (org.apache.derby.iapi.sql.dictionary.IndexRowGenerator)2 ArrayList (java.util.ArrayList)1 FormatableBitSet (org.apache.derby.iapi.services.io.FormatableBitSet)1 JoinStrategy (org.apache.derby.iapi.sql.compile.JoinStrategy)1 Optimizable (org.apache.derby.iapi.sql.compile.Optimizable)1 OptimizerPlan (org.apache.derby.iapi.sql.compile.OptimizerPlan)1 ConglomerateDescriptor (org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor)1 TableDescriptor (org.apache.derby.iapi.sql.dictionary.TableDescriptor)1 StoreCostController (org.apache.derby.iapi.store.access.StoreCostController)1 DataValueDescriptor (org.apache.derby.iapi.types.DataValueDescriptor)1 JBitSet (org.apache.derby.iapi.util.JBitSet)1