Index: src/analyze.c ================================================================== --- src/analyze.c +++ src/analyze.c @@ -1527,11 +1527,23 @@ } aiRowEst = pIndex->aiRowEst; #endif pIndex->bUnordered = 0; decodeIntArray((char*)z, nCol, aiRowEst, pIndex->aiRowLogEst, pIndex); - if( pIndex->pPartIdxWhere==0 ) pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + if( pIndex->pPartIdxWhere==0 ){ + int i, j; + /* TUNING: Any column that cannot narrow down the number of table rows + ** to less than 30 should not be considered as a column for use in + ** an automatic index */ + for(i=0; i49 && (j = pIndex->aiColumn[i])>=0 ){ + pTable->aCol[j].colFlags |= COLFLAG_NOAUTO; + } + } + pTable->nRowLogEst = pIndex->aiRowLogEst[0]; + } }else{ Index fakeIdx; fakeIdx.szIdxRow = pTable->szTabRow; #ifdef SQLITE_ENABLE_COSTMULT fakeIdx.pTable = pTable; Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -3151,12 +3151,20 @@ }else{ j = pCExpr->iColumn; assert( j<=0x7fff ); if( j<0 ){ j = pTab->iPKey; - }else if( pTab->aCol[j].notNull==0 ){ - pIndex->uniqNotNull = 0; + }else{ + if( pTab->aCol[j].notNull==0 ){ + pIndex->uniqNotNull = 0; + } + if( i==0 && pPIWhere==0 ){ + /* Exclude the left-most column of every complete index from + ** consideration as an automatic index term. Better to use the real + ** index */ + pTab->aCol[j].colFlags |= COLFLAG_NOAUTO; + } } pIndex->aiColumn[i] = (i16)j; } zColl = 0; if( pListItem->pExpr->op==TK_COLLATE ){ Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -1538,10 +1538,11 @@ /* Allowed values for Column.colFlags: */ #define COLFLAG_PRIMKEY 0x0001 /* Column is part of the primary key */ #define COLFLAG_HIDDEN 0x0002 /* A hidden column in a virtual table */ +#define COLFLAG_NOAUTO 0x0004 /* Not useful in an automatic index */ /* ** A "Collating Sequence" is defined by an instance of the following ** structure. Conceptually, a collating sequence consists of a name and ** a comparison routine that defines the order of that sequence. Index: src/where.c ================================================================== --- src/where.c +++ src/where.c @@ -576,19 +576,23 @@ ** index existed. */ static int termCanDriveIndex( WhereTerm *pTerm, /* WHERE clause term to check */ struct SrcList_item *pSrc, /* Table we are trying to access */ - Bitmask notReady /* Tables in outer loops of the join */ + Bitmask notReady, /* Tables in outer loops of the join */ + int excludeNoauto /* Answer FALSE if pTerm is COLFLAG_NOAUTO */ ){ char aff; + Column *pCol; if( pTerm->leftCursor!=pSrc->iCursor ) return 0; if( (pTerm->eOperator & (WO_EQ|WO_IS))==0 ) return 0; if( (pTerm->prereqRight & notReady)!=0 ) return 0; if( pTerm->u.leftColumn<0 ) return 0; - aff = pSrc->pTab->aCol[pTerm->u.leftColumn].affinity; + pCol = &pSrc->pTab->aCol[pTerm->u.leftColumn]; + aff = pCol->affinity; if( !sqlite3IndexAffinityOk(pTerm->pExpr, aff) ) return 0; + if( excludeNoauto && (pCol->colFlags & COLFLAG_NOAUTO)!=0 ) return 0; testcase( pTerm->pExpr->op==TK_IS ); return 1; } #endif @@ -653,11 +657,11 @@ && !ExprHasProperty(pExpr, EP_FromJoin) && sqlite3ExprIsTableConstant(pExpr, pSrc->iCursor) ){ pPartial = sqlite3ExprAnd(pParse->db, pPartial, sqlite3ExprDup(pParse->db, pExpr, 0)); } - if( termCanDriveIndex(pTerm, pSrc, notReady) ){ + if( termCanDriveIndex(pTerm, pSrc, notReady, 0) ){ int iCol = pTerm->u.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); if( !sentWarning ){ @@ -706,11 +710,11 @@ pIdx->zName = "auto-index"; pIdx->pTable = pTable; n = 0; idxCols = 0; for(pTerm=pWC->a; pTermu.leftColumn; Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS-1 ); testcase( iCol==BMS ); if( (idxCols & cMask)==0 ){ @@ -2625,11 +2629,11 @@ /* Generate auto-index WhereLoops */ WhereTerm *pTerm; WhereTerm *pWCEnd = pWC->a + pWC->nTerm; for(pTerm=pWC->a; rc==SQLITE_OK && pTermprereqRight & pNew->maskSelf ) continue; - if( termCanDriveIndex(pTerm, pSrc, 0) ){ + if( termCanDriveIndex(pTerm, pSrc, 0, 1) ){ pNew->u.btree.nEq = 1; pNew->nSkip = 0; pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm;