Index: src/build.c ================================================================== --- src/build.c +++ src/build.c @@ -3925,14 +3925,17 @@ assert( p->nSrc>0 ); pItem = &p->a[p->nSrc-1]; assert( pItem->fg.notIndexed==0 ); assert( pItem->fg.isIndexedBy==0 ); assert( pItem->fg.isTabFunc==0 ); - if( pIndexedBy->n==1 && !pIndexedBy->z ){ - /* A "NOT INDEXED" clause was supplied. See parse.y - ** construct "indexed_opt" for details. */ - pItem->fg.notIndexed = 1; + if( pIndexedBy->n>=1 && !pIndexedBy->z ){ + if( pIndexedBy->n==1 ){ + pItem->fg.notIndexed = 1; + }else{ + assert( pIndexedBy->n==2 ); + pItem->fg.useAutoIdx = 1; + } }else{ pItem->u1.zIndexedBy = sqlite3NameFromToken(pParse->db, pIndexedBy); pItem->fg.isIndexedBy = 1; } } Index: src/parse.y ================================================================== --- src/parse.y +++ src/parse.y @@ -650,15 +650,16 @@ A = sqlite3SrcListAppendFromTerm(pParse,A,&Y,&D,&Z,0,N,U); sqlite3SrcListFuncArgs(pParse, A, E); } %ifndef SQLITE_OMIT_SUBQUERY seltablist(A) ::= stl_prefix(A) LP select(S) RP - as(Z) on_opt(N) using_opt(U). { + as(Z) indexed_opt(I) on_opt(N) using_opt(U). { A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,S,N,U); + sqlite3SrcListIndexedBy(pParse, A, &I); } seltablist(A) ::= stl_prefix(A) LP seltablist(F) RP - as(Z) on_opt(N) using_opt(U). { + as(Z) indexed_opt(I) on_opt(N) using_opt(U). { if( A==0 && Z.n==0 && N==0 && U==0 ){ A = F; }else if( F->nSrc==1 ){ A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,0,N,U); if( A ){ @@ -675,10 +676,11 @@ Select *pSubquery; sqlite3SrcListShiftJoinType(F); pSubquery = sqlite3SelectNew(pParse,0,F,0,0,0,0,SF_NestedFrom,0); A = sqlite3SrcListAppendFromTerm(pParse,A,0,0,&Z,pSubquery,N,U); } + sqlite3SrcListIndexedBy(pParse, A, &I); } %endif SQLITE_OMIT_SUBQUERY %type dbnm {Token} dbnm(A) ::= . {A.z=0; A.n=0;} @@ -749,10 +751,11 @@ // %type indexed_opt {Token} indexed_opt(A) ::= . {A.z=0; A.n=0;} indexed_opt(A) ::= INDEXED BY nm(X). {A = X;} indexed_opt(A) ::= NOT INDEXED. {A.z=0; A.n=1;} +indexed_opt(A) ::= INDEXED. {A.z=0; A.n=2;} %type using_opt {IdList*} %destructor using_opt {sqlite3IdListDelete(pParse->db, $$);} using_opt(U) ::= USING LP idlist(L) RP. {U = L;} using_opt(U) ::= . {U = 0;} Index: src/sqliteInt.h ================================================================== --- src/sqliteInt.h +++ src/sqliteInt.h @@ -2606,10 +2606,11 @@ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ + unsigned useAutoIdx :1; /* Use an automatic index if possible */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<rSetup = rLogSize + rSize + 4; if( pTab->pSelect==0 && (pTab->tabFlags & TF_Ephemeral)==0 ){ pNew->rSetup += 24; } ApplyCostMultiplier(pNew->rSetup, pTab->costMult); - if( pNew->rSetup<0 ) pNew->rSetup = 0; + if( pNew->rSetup<0 || pSrc->fg.useAutoIdx ) pNew->rSetup = 0; /* TUNING: Each index lookup yields 20 rows in the table. This ** is more than the usual guess of 10 rows, since we have no way ** of knowing how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==sqlite3LogEst(20) ); @@ -4003,13 +4003,16 @@ Bitmask maskNew; /* Mask of src visited by (..) */ Bitmask revMask = 0; /* Mask of rev-order loops for (..) */ if( (pWLoop->prereq & ~pFrom->maskLoop)!=0 ) continue; if( (pWLoop->maskSelf & pFrom->maskLoop)!=0 ) continue; - if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 && pFrom->nRow<10 ){ + if( (pWLoop->wsFlags & WHERE_AUTO_INDEX)!=0 + && (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 + && pWInfo->iLimit<10 + ){ /* Do not use an automatic index if the this loop is expected - ** to run less than 2 times. */ + ** to run less than twice due to a LIMIT clause. */ assert( 10==sqlite3LogEst(2) ); continue; } /* At this point, pWLoop is a candidate to be the next loop. ** Compute its cost */