Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add the SQLITE_DEFAULT_AUTOMATIC_INDEX compile-time option, which if set to zero turns automatic indices off by default. Increase the estimated cost of an automatic index. Additional minor refactoring of the automatic index code. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
459b3179023c2c45994ea4acbf34ed5f |
User & Date: | drh 2013-06-28 21:12:20.682 |
Context
2013-06-28
| ||
23:55 | Issue the new SQLITE_WARNING_AUTOINDEX warning on the SQLite log whenever an automatic index is created. (check-in: 338826ef3f user: drh tags: trunk) | |
21:12 | Add the SQLITE_DEFAULT_AUTOMATIC_INDEX compile-time option, which if set to zero turns automatic indices off by default. Increase the estimated cost of an automatic index. Additional minor refactoring of the automatic index code. (check-in: 459b317902 user: drh tags: trunk) | |
19:41 | Allow read transactions to be freely opened and closed by SQL statements run from within the implementation of user-functions if the user-function is called by a SELECT statement that does not access any database tables (e.g. "SELECT user_function();"). (check-in: f308c48517 user: dan tags: trunk) | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
2447 2448 2449 2450 2451 2452 2453 | assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; | | > > > | 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 | assert( sizeof(db->aLimit)==sizeof(aHardLimit) ); memcpy(db->aLimit, aHardLimit, sizeof(db->aLimit)); db->autoCommit = 1; db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger #if !defined(SQLITE_DEAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX | SQLITE_AutoIndex #endif #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif #ifdef SQLITE_ENABLE_LOAD_EXTENSION | SQLITE_LoadExtension #endif #if SQLITE_DEFAULT_RECURSIVE_TRIGGERS |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
440 441 442 443 444 445 446 | #define WHERE_IDX_ONLY 0x00000040 /* Use index only - omit table */ #define WHERE_IPK 0x00000100 /* x is the INTEGER PRIMARY KEY */ #define WHERE_INDEXED 0x00000200 /* WhereLoop.u.btree.pIndex is valid */ #define WHERE_VIRTUALTABLE 0x00000400 /* WhereLoop.u.vtab is valid */ #define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */ #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ | | | 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | #define WHERE_IDX_ONLY 0x00000040 /* Use index only - omit table */ #define WHERE_IPK 0x00000100 /* x is the INTEGER PRIMARY KEY */ #define WHERE_INDEXED 0x00000200 /* WhereLoop.u.btree.pIndex is valid */ #define WHERE_VIRTUALTABLE 0x00000400 /* WhereLoop.u.vtab is valid */ #define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */ #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ #define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */ /* Convert a WhereCost value (10 times log2(X)) into its integer value X. ** A rough approximation is used. The value returned is not exact. */ static u64 whereCostToInt(WhereCost x){ u64 n; |
︙ | ︙ | |||
2068 2069 2070 2071 2072 2073 2074 | idxCols |= cMask; } } } assert( nColumn>0 ); pLoop->u.btree.nEq = pLoop->nLTerm = nColumn; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED | | | 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 | idxCols |= cMask; } } } assert( nColumn>0 ); pLoop->u.btree.nEq = pLoop->nLTerm = nColumn; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED | WHERE_AUTO_INDEX; /* Count the number of additional columns needed to create a ** covering index. A "covering index" is an index that contains all ** columns that are needed by the query. With a covering index, the ** original table never needs to be accessed. Automatic indices must ** be a covering index because the index will not be updated if the ** original table changes and the index and table cannot both be used |
︙ | ︙ | |||
3114 3115 3116 3117 3118 3119 3120 | if( pItem->zAlias ){ zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); } if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 && ALWAYS(pLoop->u.btree.pIndex!=0) ){ char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); | | | > > | < | < < | 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 | if( pItem->zAlias ){ zMsg = sqlite3MAppendf(db, zMsg, "%s AS %s", zMsg, pItem->zAlias); } if( (flags & (WHERE_IPK|WHERE_VIRTUALTABLE))==0 && ALWAYS(pLoop->u.btree.pIndex!=0) ){ char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); zMsg = sqlite3MAppendf(db, zMsg, ((flags & WHERE_AUTO_INDEX) ? "%s USING AUTOMATIC %sINDEX%.0s%s" : "%s USING %sINDEX %s%s"), zMsg, ((flags & WHERE_IDX_ONLY) ? "COVERING " : ""), pLoop->u.btree.pIndex->zName, zWhere); sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); if( flags&(WHERE_COLUMN_EQ|WHERE_COLUMN_IN) ){ zMsg = sqlite3MAppendf(db, zMsg, "%s (rowid=?)", zMsg); }else if( (flags&WHERE_BOTH_LIMIT)==WHERE_BOTH_LIMIT ){ |
︙ | ︙ | |||
3791 3792 3793 3794 3795 3796 3797 | ** uses an index, and this is either the first OR-connected term ** processed or the index is the same as that used by all previous ** terms, set pCov to the candidate covering index. Otherwise, set ** pCov to NULL to indicate that no candidate covering index will ** be available. */ pSubLoop = pSubWInfo->a[0].pWLoop; | | | 3790 3791 3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 | ** uses an index, and this is either the first OR-connected term ** processed or the index is the same as that used by all previous ** terms, set pCov to the candidate covering index. Otherwise, set ** pCov to NULL to indicate that no candidate covering index will ** be available. */ pSubLoop = pSubWInfo->a[0].pWLoop; assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) ){ assert( pSubWInfo->a[0].iIdxCur==iCovCur ); pCov = pSubLoop->u.btree.pIndex; }else{ pCov = 0; |
︙ | ︙ | |||
3973 3974 3975 3976 3977 3978 3979 | p->wsFlags = 0; } /* ** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. */ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ | | | | 3972 3973 3974 3975 3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 | p->wsFlags = 0; } /* ** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. */ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ if( p->wsFlags & (WHERE_VIRTUALTABLE|WHERE_AUTO_INDEX) ){ if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 && p->u.vtab.needFree ){ sqlite3_free(p->u.vtab.idxStr); p->u.vtab.needFree = 0; p->u.vtab.idxStr = 0; }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); sqlite3DbFree(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; } } } |
︙ | ︙ | |||
4021 4022 4023 4024 4025 4026 4027 | static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ if( whereLoopResize(db, pTo, pFrom->nLTerm) ) return SQLITE_NOMEM; whereLoopClearUnion(db, pTo); memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ pFrom->u.vtab.needFree = 0; | | | 4020 4021 4022 4023 4024 4025 4026 4027 4028 4029 4030 4031 4032 4033 4034 | static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ if( whereLoopResize(db, pTo, pFrom->nLTerm) ) return SQLITE_NOMEM; whereLoopClearUnion(db, pTo); memcpy(pTo, pFrom, WHERE_LOOP_XFER_SZ); memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ pFrom->u.vtab.needFree = 0; }else if( (pFrom->wsFlags & WHERE_AUTO_INDEX)!=0 ){ pFrom->u.btree.pIndex = 0; } return SQLITE_OK; } /* ** Delete a WhereLoop object |
︙ | ︙ | |||
4494 4495 4496 4497 4498 4499 4500 | if( pTerm->prereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is | | | | > > > | | | 4493 4494 4495 4496 4497 4498 4499 4500 4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 | if( pTerm->prereqRight & pNew->maskSelf ) continue; if( termCanDriveIndex(pTerm, pSrc, 0) ){ pNew->u.btree.nEq = 1; pNew->u.btree.pIndex = 0; pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is ** approximately 7*N*log2(N) where N is the number of rows in ** the table being indexed. */ pNew->rSetup = rLogSize + rSize + 28; assert( 28==whereCost(7) ); /* 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 knowning how selective the index will ultimately be. It would ** not be unreasonable to make this value much larger. */ pNew->nOut = 43; assert( 43==whereCost(20) ); pNew->rRun = whereCostAdd(rLogSize,pNew->nOut); pNew->wsFlags = WHERE_AUTO_INDEX; pNew->prereq = mExtra | pTerm->prereqRight; rc = whereLoopInsert(pBuilder, pNew); } } } /* Loop over all indices |
︙ | ︙ | |||
5877 5878 5879 5880 5881 5882 5883 | SQLITE_INT_TO_PTR(n), P4_INT32); assert( n<=pTab->nCol ); } }else{ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX | | | 5879 5880 5881 5882 5883 5884 5885 5886 5887 5888 5889 5890 5891 5892 5893 | SQLITE_INT_TO_PTR(n), P4_INT32); assert( n<=pTab->nCol ); } }else{ sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX if( (pLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, pTabItem, notReady, pLevel); }else #endif if( pLoop->wsFlags & WHERE_INDEXED ){ Index *pIx = pLoop->u.btree.pIndex; KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIx); /* FIXME: As an optimization use pTabItem->iCursor if WHERE_IDX_ONLY */ |
︙ | ︙ | |||
6000 6001 6002 6003 6004 6005 6006 | && pTab->pSelect==0 && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ int ws = pLoop->wsFlags; if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } | | | 6002 6003 6004 6005 6006 6007 6008 6009 6010 6011 6012 6013 6014 6015 6016 | && pTab->pSelect==0 && (pWInfo->wctrlFlags & WHERE_OMIT_OPEN_CLOSE)==0 ){ int ws = pLoop->wsFlags; if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); } } /* If this scan uses an index, make VDBE code substitutions to read data ** from the index instead of from the table where possible. In some cases ** this optimization prevents the table from ever being read, which can |
︙ | ︙ |
Changes to test/autoindex1.test.
︙ | ︙ | |||
90 91 92 93 94 95 96 97 98 | do_test autoindex1-212 { db status autoindex } {7} # Modify the second table of the join while the join is in progress # do_test autoindex1-300 { set r {} | > > > > > > | | 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | do_test autoindex1-212 { db status autoindex } {7} # Modify the second table of the join while the join is in progress # do_execsql_test autoindex1-299 { UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t2'; ANALYZE sqlite_master; EXPLAIN QUERY PLAN SELECT b, d FROM t1 CROSS JOIN t2 ON (c=a); } {/AUTOMATIC COVERING INDEX/} do_test autoindex1-300 { set r {} db eval {SELECT b, d FROM t1 CROSS JOIN t2 ON (c=a)} { lappend r $b $d db eval {UPDATE t2 SET d=d+1} } set r } {11 911 22 922 33 933 44 944 55 955 66 966 77 977 88 988} do_test autoindex1-310 { db eval {SELECT d FROM t2 ORDER BY d} |
︙ | ︙ |