/ Check-in [adbdc663]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Continued refactoring of the ORDER BY optimization logic. This check-in is close to working, but it still has issues. A few test cases fail.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | qp-enhancements
Files: files | file ages | folders
SHA1: adbdc663f3d22ff03f21040a811d585cf2218626
User & Date: drh 2012-10-08 18:23:51
Context
2012-10-08
19:41
Bug fixes in the ORDER BY optimizer. check-in: 301bbee4 user: drh tags: qp-enhancements
18:23
Continued refactoring of the ORDER BY optimization logic. This check-in is close to working, but it still has issues. A few test cases fail. check-in: adbdc663 user: drh tags: qp-enhancements
2012-10-04
12:10
Yet another refactoring of ORDER BY logic in the query planner. This particular check-in works mostly, but still has a few minor issues. check-in: 8f448745 user: drh tags: qp-enhancements
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/where.c.

  2708   2708     }
  2709   2709     return rc;
  2710   2710   }
  2711   2711   #endif /* defined(SQLITE_ENABLE_STAT3) */
  2712   2712   
  2713   2713   /*
  2714   2714   ** Check to see if column iCol of the table with cursor iTab will appear
  2715         -** in sorted order according to the current query plan.  Return true if
  2716         -** it will and false if not.  
         2715  +** in sorted order according to the current query plan.
  2717   2716   **
  2718         -** If *pbRev is initially 2 (meaning "unknown") then set *pbRev to the
  2719         -** sort order of iTab.iCol.  If *pbRev is 0 or 1 but does not match
  2720         -** the sort order of iTab.iCol, then consider the column to be unordered.
         2717  +** Return values:
         2718  +**
         2719  +**    0   iCol is not ordered
         2720  +**    1   iCol has only a single value
         2721  +**    2   iCol is in ASC order
         2722  +**    3   iCol is in DESC order
  2721   2723   */
  2722         -static int isOrderedColumn(WhereBestIdx *p, int iTab, int iCol, int *pbRev){
         2724  +static int isOrderedColumn(
         2725  +  WhereBestIdx *p,
         2726  +  int iTab,
         2727  +  int iCol
         2728  +){
  2723   2729     int i, j;
  2724   2730     WhereLevel *pLevel = &p->aLevel[p->i-1];
  2725   2731     Index *pIdx;
  2726   2732     u8 sortOrder;
  2727   2733     for(i=p->i-1; i>=0; i--, pLevel--){
  2728   2734       if( pLevel->iTabCur!=iTab ) continue;
  2729   2735       if( (pLevel->plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
................................................................................
  2751   2757         testcase( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 );
  2752   2758       }
  2753   2759       if( (pLevel->plan.wsFlags & WHERE_REVERSE)!=0 ){
  2754   2760         assert( sortOrder==0 || sortOrder==1 );
  2755   2761         testcase( sortOrder==1 );
  2756   2762         sortOrder = 1 - sortOrder;
  2757   2763       }
  2758         -    if( *pbRev==2 ){
  2759         -      *pbRev = sortOrder;
  2760         -      return 1;
  2761         -    }
  2762         -    return (*pbRev==sortOrder);
         2764  +    return sortOrder+2;
  2763   2765     }
  2764   2766     return 0;
  2765   2767   }
  2766   2768   
  2767         -/*
  2768         -** Check to see if there is an == or IS NULL constraint in the WHERE clause
  2769         -** that restricts base.iColumn to be well-ordered.  If base.iColumn must
  2770         -** be a constant or must be NULL, that qualifies as well-ordered.  If
  2771         -** base.iColumn must equal the value of a column in an outer loop that is
  2772         -** ordered, that also qualifies as being well ordered.
  2773         -**
  2774         -** In the second case (when base.iColumn == an ordered value in an outer
  2775         -** loop) set or verify the sort order.  If *pbRev is initially 2, then set
  2776         -** it approprately.  If *pbRev is 0 or 1, make sure it matches the sort
  2777         -** order of the outer loop constraint.
  2778         -*/
  2779         -static int existsEqualityColumnConstraint(
  2780         -  WhereBestIdx *p,    /* Best index search context */
  2781         -  Index *pIdx,        /* Constraint must be compatible with this index */
  2782         -  int base,           /* Cursor number for the table to be sorted */
  2783         -  int iColumn,        /* Index of a column on the "base" table */
  2784         -  int *pbRev,         /* Set to 1 for reverse-order constraint */
  2785         -  int *notNull        /* Set to 0 if an IS NULL constraint is seen */
  2786         -){
  2787         -  WhereTerm *pTerm;
  2788         -  int rc;
  2789         -
  2790         -WHERETRACE(("EQ Constraint on %d.%d: pbRev-in=%d", base, iColumn, *pbRev));
  2791         -  pTerm = findTerm(p->pWC, base, iColumn, p->notReady, WO_EQ|WO_ISNULL, pIdx);
  2792         -  if( pTerm==0 ){
  2793         -    rc = 0;
  2794         -  }else if( pTerm->prereqRight==0 ){
  2795         -    rc = 1;
  2796         -  }else if( pTerm->eOperator & WO_ISNULL ){
  2797         -    *notNull = 0;
  2798         -    rc = 1;
  2799         -  }else{
  2800         -    Expr *pRight = pTerm->pExpr->pRight;
  2801         -    if( pRight->op==TK_COLUMN ){
  2802         -      rc = isOrderedColumn(p, pRight->iTable, pRight->iColumn, pbRev);
  2803         -    }else{
  2804         -      rc = 0;
  2805         -    }
  2806         -  }
  2807         -WHERETRACE((" rc=%d pbRev-out=%d\n", rc, *pbRev));
  2808         -  return rc;
  2809         -}
  2810         -  
  2811         -
  2812   2769   /*
  2813   2770   ** This routine decides if pIdx can be used to satisfy the ORDER BY
  2814   2771   ** clause, either in whole or in part.  The return value is the 
  2815   2772   ** cumulative number of terms in the ORDER BY clause that are satisfied
  2816   2773   ** by the index pIdx and other indices in outer loops.
  2817   2774   **
  2818   2775   ** The table being queried has a cursor number of "base".  pIdx is the
................................................................................
  2835   2792     int base,           /* Cursor number for the table to be sorted */
  2836   2793     int *pbRev          /* Set to 1 for reverse-order scan of pIdx */
  2837   2794   ){
  2838   2795     int i;                        /* Number of pIdx terms used */
  2839   2796     int j;                        /* Number of ORDER BY terms satisfied */
  2840   2797     int sortOrder = 2;            /* 0: forward.  1: backward.  2: unknown */
  2841   2798     int nTerm;                    /* Number of ORDER BY terms */
  2842         -  struct ExprList_item *pTerm;  /* A term of the ORDER BY clause */
         2799  +  struct ExprList_item *pOBItem;/* A term of the ORDER BY clause */
  2843   2800     Table *pTab = pIdx->pTable;   /* Table that owns index pIdx */
  2844   2801     ExprList *pOrderBy;           /* The ORDER BY clause */
  2845   2802     Parse *pParse = p->pParse;    /* Parser context */
  2846   2803     sqlite3 *db = pParse->db;     /* Database connection */
  2847   2804     int nPriorSat;                /* ORDER BY terms satisfied by outer loops */
  2848   2805     int seenRowid = 0;            /* True if an ORDER BY rowid term is seen */
  2849   2806     int uniqueNotNull = 1;        /* pIdx is UNIQUE with all terms are NOT NULL */
................................................................................
  2854   2811       nPriorSat = p->aLevel[p->i-1].plan.nOBSat;
  2855   2812       if( OptimizationDisabled(db, SQLITE_OrderByIdxJoin) ) return nPriorSat;
  2856   2813     }
  2857   2814     pOrderBy = p->pOrderBy;
  2858   2815     assert( pOrderBy!=0 );
  2859   2816     if( pIdx->bUnordered ) return nPriorSat;
  2860   2817     nTerm = pOrderBy->nExpr;
  2861         -  uniqueNotNull = pIdx->onError==OE_None;
         2818  +  uniqueNotNull = pIdx->onError!=OE_None;
  2862   2819     assert( nTerm>0 );
  2863   2820   
  2864   2821     /* Argument pIdx must either point to a 'real' named index structure, 
  2865   2822     ** or an index structure allocated on the stack by bestBtreeIndex() to
  2866   2823     ** represent the rowid index that is part of every table.  */
  2867   2824     assert( pIdx->zName || (pIdx->nColumn==1 && pIdx->aiColumn[0]==-1) );
  2868   2825   
................................................................................
  2870   2827     ** the index.
  2871   2828     **
  2872   2829     ** Note that indices have pIdx->nColumn regular columns plus
  2873   2830     ** one additional column containing the rowid.  The rowid column
  2874   2831     ** of the index is also allowed to match against the ORDER BY
  2875   2832     ** clause.
  2876   2833     */
  2877         -  for(i=0,j=nPriorSat,pTerm=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){
  2878         -    Expr *pExpr;       /* The expression of the ORDER BY pTerm */
  2879         -    CollSeq *pColl;    /* The collating sequence of pExpr */
  2880         -    int termSortOrder; /* Sort order for this term */
  2881         -    int iColumn;       /* The i-th column of the index.  -1 for rowid */
  2882         -    int iSortOrder;    /* 1 for DESC, 0 for ASC on the i-th index term */
  2883         -    int isEq;          /* Subject to an == or IS NULL constraint */
  2884         -    const char *zColl; /* Name of the collating sequence for i-th index term */
         2834  +  j = nPriorSat;
         2835  +  for(i=0,pOBItem=&pOrderBy->a[j]; j<nTerm && i<=pIdx->nColumn; i++){
         2836  +    Expr *pOBExpr;          /* The expression of the ORDER BY pOBItem */
         2837  +    CollSeq *pColl;         /* The collating sequence of pOBExpr */
         2838  +    int termSortOrder;      /* Sort order for this term */
         2839  +    int iColumn;            /* The i-th column of the index.  -1 for rowid */
         2840  +    int iSortOrder;         /* 1 for DESC, 0 for ASC on the i-th index term */
         2841  +    int isEq;               /* Subject to an == or IS NULL constraint */
         2842  +    int isMatch;            /* ORDER BY term matches the index term */
         2843  +    const char *zColl;      /* Name of collating sequence for i-th index term */
         2844  +    WhereTerm *pConstraint; /* A constraint in the WHERE clause */
  2885   2845   
  2886         -    pExpr = pTerm->pExpr;
  2887         -    if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
  2888         -      /* Can not use an index sort on anything that is not a column in the
  2889         -      ** left-most table of the FROM clause */
         2846  +    /* If the next term of the ORDER BY clause refers to anything other than
         2847  +    ** a column in the "base" table, then this index will not be of any
         2848  +    ** further use in handling the ORDER BY. */
         2849  +    pOBExpr = pOBItem->pExpr;
         2850  +    if( pOBExpr->op!=TK_COLUMN || pOBExpr->iTable!=base ){
  2890   2851         break;
  2891   2852       }
  2892         -    pColl = sqlite3ExprCollSeq(pParse, pExpr);
  2893         -    if( !pColl ){
  2894         -      pColl = db->pDfltColl;
  2895         -    }
         2853  +
         2854  +    /* Find column number and collating sequence for the next entry
         2855  +    ** in the index */
  2896   2856       if( pIdx->zName && i<pIdx->nColumn ){
  2897   2857         iColumn = pIdx->aiColumn[i];
  2898   2858         if( iColumn==pIdx->pTable->iPKey ){
  2899   2859           iColumn = -1;
  2900   2860         }
  2901   2861         iSortOrder = pIdx->aSortOrder[i];
  2902   2862         zColl = pIdx->azColl[i];
         2863  +      assert( zColl!=0 );
  2903   2864       }else{
  2904   2865         iColumn = -1;
  2905   2866         iSortOrder = 0;
  2906         -      zColl = pColl->zName;
  2907         -    }
  2908         -    assert( pTerm->sortOrder==0 || pTerm->sortOrder==1 );
  2909         -    assert( iSortOrder==0 || iSortOrder==1 );
  2910         -    termSortOrder = pTerm->sortOrder;
  2911         -    isEq = existsEqualityColumnConstraint(p, pIdx, base, iColumn,
  2912         -                                         &termSortOrder, &uniqueNotNull);
  2913         -    termSortOrder = iSortOrder ^ pTerm->sortOrder;
  2914         -    if( pExpr->iColumn!=iColumn || sqlite3StrICmp(pColl->zName, zColl) ){
  2915         -      /* Term j of the ORDER BY clause does not match column i of the index */
  2916         -      if( isEq ){
  2917         -        /* If an index column that is constrained by == or IS NULL fails to
  2918         -        ** match an ORDER BY term, that is OK.  Just ignore that column of
  2919         -        ** the index
  2920         -        */
  2921         -        continue;
         2867  +      zColl = 0;
         2868  +    }
         2869  +
         2870  +    /* Check to see if the column number and collating sequence of the
         2871  +    ** index match the column number and collating sequence of the ORDER BY
         2872  +    ** clause entry.  Set isMatch to 1 if they both match. */
         2873  +    if( pOBExpr->iColumn==iColumn ){
         2874  +      if( zColl ){
         2875  +        pColl = sqlite3ExprCollSeq(pParse, pOBExpr);
         2876  +        if( !pColl ) pColl = db->pDfltColl;
         2877  +        isMatch = sqlite3StrICmp(pColl->zName, zColl)==0;
         2878  +      }else{
         2879  +        isMatch = 1;
         2880  +      }
         2881  +    }else{
         2882  +      isMatch = 0;
         2883  +    }
         2884  +
         2885  +    /* termSortOrder is 0 or 1 for whether or not the access loop should
         2886  +    ** run forward or backwards (respectively) in order to satisfy this 
         2887  +    ** term of the ORDER BY clause. */
         2888  +    termSortOrder = iSortOrder ^ pOBItem->sortOrder;
         2889  +
         2890  +    /* If X is the column in the index and ORDER BY clause, check to see
         2891  +    ** if there are any X= or X IS NULL constraints in the WHERE clause. */
         2892  +    pConstraint = findTerm(p->pWC, base, iColumn, p->notReady,
         2893  +                           WO_EQ|WO_ISNULL|WO_IN, pIdx);
         2894  +    if( pConstraint==0 ){
         2895  +      isEq = 0;
         2896  +    }else if( pConstraint->eOperator==WO_IN ){
         2897  +      break;
         2898  +    }else if( pConstraint->prereqRight==0 ){
         2899  +      isEq = 1;
         2900  +    }else if( pConstraint->eOperator==WO_ISNULL ){
         2901  +      uniqueNotNull = 0;
         2902  +      isEq = 1;
         2903  +    }else{
         2904  +      Expr *pRight = pConstraint->pExpr->pRight;
         2905  +      if( pRight->op==TK_COLUMN ){
         2906  +        WHERETRACE(("       .. isOrderedColumn(tab=%d,col=%d)",
         2907  +                    pRight->iTable, pRight->iColumn));
         2908  +        isEq = isOrderedColumn(p, pRight->iTable, pRight->iColumn);
         2909  +        WHERETRACE((" -> isEq=%d\n", isEq));
         2910  +        if( isEq>=2 && isEq!=pOBItem->sortOrder+2 ){
         2911  +          break;
         2912  +        }
  2922   2913         }else{
  2923         -        /* If an index column fails to match and is not constrained by ==
  2924         -        ** then the index cannot satisfy the ORDER BY constraint.
  2925         -        */
  2926         -        return nPriorSat;
         2914  +        isEq = 0;
  2927   2915         }
  2928   2916       }
  2929         -    if( sortOrder<2 ){
  2930         -      if( sortOrder!=termSortOrder ){
  2931         -        /* Indices can only be used if all ORDER BY terms past the
  2932         -        ** equality constraints have the correct DESC or ASC. */
         2917  +    assert( pOBItem->sortOrder==0 || pOBItem->sortOrder==1 );
         2918  +    assert( iSortOrder==0 || iSortOrder==1 );
         2919  +    if( !isMatch ){
         2920  +      if( isEq==0 ){
  2933   2921           break;
         2922  +      }else{
         2923  +        continue;
  2934   2924         }
  2935         -    }else{
         2925  +    }else if( sortOrder==2 ){
  2936   2926         sortOrder = termSortOrder;
         2927  +    }else if( termSortOrder!=sortOrder ){
         2928  +      break;
  2937   2929       }
  2938   2930       j++;
  2939         -    pTerm++;
         2931  +    pOBItem++;
  2940   2932       if( iColumn<0 ){
  2941   2933         seenRowid = 1;
  2942   2934         break;
  2943   2935       }else if( pTab->aCol[iColumn].notNull==0 ){
  2944   2936         uniqueNotNull = 0;
  2945   2937       }
  2946   2938     }
................................................................................
  3053   3045     /* Loop over all indices looking for the best one to use
  3054   3046     */
  3055   3047     for(; pProbe; pIdx=pProbe=pProbe->pNext){
  3056   3048       const tRowcnt * const aiRowEst = pProbe->aiRowEst;
  3057   3049       WhereCost pc;               /* Cost of using pProbe */
  3058   3050       double log10N = (double)1;  /* base-10 logarithm of nRow (inexact) */
  3059   3051       int bRev = 2;               /* 0=forward scan.  1=reverse.  2=undecided */
         3052  +
         3053  +    WHERETRACE((
         3054  +      "   %s(%s):\n",
         3055  +      pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk")
         3056  +    ));
  3060   3057   
  3061   3058       /* The following variables are populated based on the properties of
  3062   3059       ** index being evaluated. They are then used to determine the expected
  3063   3060       ** cost and number of rows returned.
  3064   3061       **
  3065   3062       **  pc.plan.nEq: 
  3066   3063       **    Number of equality terms that can be implemented using the index.
................................................................................
  3221   3218   
  3222   3219       /* If there is an ORDER BY clause and the index being considered will
  3223   3220       ** naturally scan rows in the required order, set the appropriate flags
  3224   3221       ** in pc.plan.wsFlags. Otherwise, if there is an ORDER BY clause but
  3225   3222       ** the index will scan rows in a different order, set the bSort
  3226   3223       ** variable.  */
  3227   3224       assert( bRev>=0 && bRev<=2 );
  3228         -    if( bSort ){
  3229         -      testcase( bRev==0 );
  3230         -      testcase( bRev==1 );
  3231         -      testcase( bRev==2 );
  3232         -WHERETRACE(("--> before isSortingIndex: bRev=%d nPriorSat=%d\n", bRev, nPriorSat));
         3225  +    if( bSort && (pSrc->jointype & JT_LEFT)==0 ){
         3226  +      int bRev = 2;
         3227  +      WHERETRACE(("      --> before isSortingIndex: nPriorSat=%d\n",nPriorSat));
  3233   3228         pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
  3234         -WHERETRACE(("--> after  isSortingIndex: bRev=%d nOBSat=%d\n", bRev, pc.plan.nOBSat));
         3229  +      WHERETRACE(("      --> after  isSortingIndex: bRev=%d nOBSat=%d\n",
         3230  +                  bRev, pc.plan.nOBSat));
  3235   3231         if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
  3236   3232           pc.plan.wsFlags |= WHERE_ORDERED;
  3237   3233         }
  3238   3234         if( nOrderBy==pc.plan.nOBSat ){
  3239   3235           bSort = 0;
  3240   3236           pc.plan.wsFlags |= WHERE_ROWID_RANGE|WHERE_COLUMN_RANGE;
  3241   3237         }
................................................................................
  3345   3341         ** the cost function to err on the side of choosing an index over
  3346   3342         ** choosing a full scan.  This 4x full-scan penalty is an arguable
  3347   3343         ** decision and one which we expect to revisit in the future.  But
  3348   3344         ** it seems to be working well enough at the moment.
  3349   3345         */
  3350   3346         pc.rCost = aiRowEst[0]*4;
  3351   3347         pc.plan.wsFlags &= ~WHERE_IDX_ONLY;
  3352         -      if( pIdx ) pc.plan.wsFlags &= ~WHERE_ORDERED;
         3348  +      if( pIdx ){
         3349  +        pc.plan.wsFlags &= ~WHERE_ORDERED;
         3350  +        pc.plan.nOBSat = nPriorSat;
         3351  +      }
  3353   3352       }else{
  3354   3353         log10N = estLog(aiRowEst[0]);
  3355   3354         pc.rCost = pc.plan.nRow;
  3356   3355         if( pIdx ){
  3357   3356           if( bLookup ){
  3358   3357             /* For an index lookup followed by a table lookup:
  3359   3358             **    nInMul index searches to find the start of each index range
................................................................................
  3450   3449           }
  3451   3450         }
  3452   3451         if( pc.plan.nRow<2 ) pc.plan.nRow = 2;
  3453   3452       }
  3454   3453   
  3455   3454   
  3456   3455       WHERETRACE((
  3457         -      "%s(%s):\n"
  3458         -      "    nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
  3459         -      "    notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
  3460         -      "    used=0x%llx nOBSat=%d\n",
  3461         -      pSrc->pTab->zName, (pIdx ? pIdx->zName : "ipk"), 
         3456  +      "      nEq=%d nInMul=%d rangeDiv=%d bSort=%d bLookup=%d wsFlags=0x%08x\n"
         3457  +      "      notReady=0x%llx log10N=%.1f nRow=%.1f cost=%.1f\n"
         3458  +      "      used=0x%llx nOBSat=%d\n",
  3462   3459         pc.plan.nEq, nInMul, (int)rangeDiv, bSort, bLookup, pc.plan.wsFlags,
  3463   3460         p->notReady, log10N, pc.plan.nRow, pc.rCost, pc.used,
  3464   3461         pc.plan.nOBSat
  3465   3462       ));
  3466   3463   
  3467   3464       /* If this index is the best we have seen so far, then record this
  3468   3465       ** index and its cost in the p->cost structure.
................................................................................
  3494   3491     assert( p->pOrderBy || (p->cost.plan.wsFlags&WHERE_ORDERED)==0 );
  3495   3492     assert( p->cost.plan.u.pIdx==0 || (p->cost.plan.wsFlags&WHERE_ROWID_EQ)==0 );
  3496   3493     assert( pSrc->pIndex==0 
  3497   3494          || p->cost.plan.u.pIdx==0 
  3498   3495          || p->cost.plan.u.pIdx==pSrc->pIndex 
  3499   3496     );
  3500   3497   
  3501         -  WHERETRACE(("best index is: %s\n",
         3498  +  WHERETRACE(("   best index is: %s\n",
  3502   3499            p->cost.plan.u.pIdx ? p->cost.plan.u.pIdx->zName : "ipk"));
  3503   3500     
  3504   3501     bestOrClauseIndex(p);
  3505   3502     bestAutomaticIndex(p);
  3506   3503     p->cost.plan.wsFlags |= eqTermMask;
  3507   3504   }
  3508   3505   
................................................................................
  5044   5041           if( (m & sWBI.notValid)==0 ){
  5045   5042             if( j==iFrom ) iFrom++;
  5046   5043             continue;
  5047   5044           }
  5048   5045           sWBI.notReady = (isOptimal ? m : sWBI.notValid);
  5049   5046           if( sWBI.pSrc->pIndex==0 ) nUnconstrained++;
  5050   5047     
  5051         -        WHERETRACE(("=== trying table %d (%s) with isOptimal=%d ===\n",
         5048  +        WHERETRACE(("   === trying table %d (%s) with isOptimal=%d ===\n",
  5052   5049                       j, sWBI.pSrc->pTab->zName, isOptimal));
  5053   5050           assert( sWBI.pSrc->pTab );
  5054   5051   #ifndef SQLITE_OMIT_VIRTUALTABLE
  5055   5052           if( IsVirtual(sWBI.pSrc->pTab) ){
  5056   5053             sWBI.ppIdxInfo = &pWInfo->a[j].pIdxInfo;
  5057   5054             bestVirtualIndex(&sWBI);
  5058   5055           }else 
................................................................................
  5097   5094               && (bestJ<0 || (notIndexed&m)!=0                     /* (2) */
  5098   5095                   || (bestPlan.plan.wsFlags & WHERE_NOT_FULLSCAN)==0
  5099   5096                   || (sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0)
  5100   5097               && (nUnconstrained==0 || sWBI.pSrc->pIndex==0        /* (3) */
  5101   5098                   || NEVER((sWBI.cost.plan.wsFlags & WHERE_NOT_FULLSCAN)!=0))
  5102   5099               && (bestJ<0 || compareCost(&sWBI.cost, &bestPlan))   /* (4) */
  5103   5100           ){
  5104         -          WHERETRACE(("=== table %d (%s) is best so far\n"
  5105         -                      "    cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
         5101  +          WHERETRACE(("   === table %d (%s) is best so far\n"
         5102  +                      "       cost=%.1f, nRow=%.1f, nOBSat=%d, wsFlags=%08x\n",
  5106   5103                         j, sWBI.pSrc->pTab->zName,
  5107   5104                         sWBI.cost.rCost, sWBI.cost.plan.nRow,
  5108   5105                         sWBI.cost.plan.nOBSat, sWBI.cost.plan.wsFlags));
  5109   5106             bestPlan = sWBI.cost;
  5110   5107             bestJ = j;
  5111   5108           }
  5112   5109           if( doNotReorder ) break;