From: drh Date: Tue, 27 Aug 2013 20:16:48 +0000 (+0000) Subject: Reduce the amount of code run and memory used for ANALYZE in the common case X-Git-Tag: version-3.8.1~129 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9fecc546cb32bf293a5f91ba9c472115577b85a5;p=thirdparty%2Fsqlite.git Reduce the amount of code run and memory used for ANALYZE in the common case where neither STAT3 and STAT4 are enabled. FossilOrigin-Name: 9d1424c91a21ed740aca53e437b8f7c1f0823c03 --- diff --git a/manifest b/manifest index bf7e78d21a..c679578fc0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\ssqlite3.pc.in\sto\suse\s@PACKAGE_VERSION@\sinstead\sof\s@RELEASE@. -D 2013-08-27T15:41:09.212 +C Reduce\sthe\samount\sof\scode\srun\sand\smemory\sused\sfor\sANALYZE\sin\sthe\scommon\scase\nwhere\sneither\sSTAT3\sand\sSTAT4\sare\senabled. +D 2013-08-27T20:16:48.420 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -157,7 +157,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c 2af0330bb1b601af7a7789bf7229675fd772a083 -F src/analyze.c ce2a3385ac05f61e07d384b1c7e8c52e6ef1a3a6 +F src/analyze.c f1dbc79cbe97f960b20dfc3d24143dff988db41d F src/attach.c fea00cab11c854646a27641a263f5876569a51f9 F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c 2f1987981139bd2f6d8c728d64bf09fb387443c3 @@ -221,7 +221,7 @@ F src/shell.c 00a23311466829d9b77f0be4f7cedee9328279db F src/sqlite.h.in bd1451ba1ab681022a53bccc3c39580ba094a3ff F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc -F src/sqliteInt.h f3636620ad376f65bdbbf5e183f0e4309cb7526e +F src/sqliteInt.h 97b1005b812048469c80ec9394a77e0ad83ea9c0 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -1107,7 +1107,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 959bb5acdc3b4e2b481e3c38f20867131bfc9dbc -R 2e3b4a437bff68926c962c9ab6977363 -U dan -Z 665cf10c770598d3c963d389b4e25d18 +P 2460dfd8825d251e622e866e8dc1c0bf7fe7ec9f +R d4ca9812963b4361724d44342b635223 +U drh +Z 6faf42c735288a2cfa68556541b907cb diff --git a/manifest.uuid b/manifest.uuid index c8cd2432dc..94e1055f64 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2460dfd8825d251e622e866e8dc1c0bf7fe7ec9f \ No newline at end of file +9d1424c91a21ed740aca53e437b8f7c1f0823c03 \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index d2fd3682ae..9ea16b91e9 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -1,5 +1,5 @@ /* -** 2005 July 8 +** 2005-07-08 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: @@ -31,7 +31,9 @@ ** SQLITE_ENABLE_STAT3 defined. The functionality of sqlite_stat3 ** is a superset of sqlite_stat2. The sqlite_stat4 is an enhanced ** version of sqlite_stat3 and is only available when compiled with -** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.0 and later. +** SQLITE_ENABLE_STAT4 and in SQLite versions 3.8.0 and later. It is +** not possible to enable both STAT3 and STAT4 at the same time. If they +** are both enabled, then STAT4 is precedence. ** ** For most applications, sqlite_stat1 provides all the statisics required ** for the query planner to make good choices. @@ -152,23 +154,23 @@ # define IsStat4 0 # define IsStat3 0 # undef SQLITE_ENABLE_STAT34 +# undef SQLITE_STAT4_SAMPLES +# define SQLITE_STAT4_SAMPLES 1 #endif +#define IsStat34 (IsStat3+IsStat4) /* 1 for STAT3 or STAT4. 0 otherwise */ /* -** This routine generates code that opens the sqlite_stat1 table for -** writing with cursor iStatCur. If the library was built with the -** SQLITE_ENABLE_STAT4 macro defined, then the sqlite_stat4 table is -** opened for writing using cursor (iStatCur+1) +** This routine generates code that opens the sqlite_statN tables. +** The sqlite_stat1 table is always relevant. sqlite_stat2 is now +** obsolete. sqlite_stat3 and sqlite_stat4 are only opened when +** appropriate compile-time options are provided. ** -** If the sqlite_stat1 tables does not previously exist, it is created. -** Similarly, if the sqlite_stat4 table does not exist and the library -** is compiled with SQLITE_ENABLE_STAT4 defined, it is created. +** If the sqlite_statN tables do not previously exist, it is created. ** ** Argument zWhere may be a pointer to a buffer containing a table name, ** or it may be a NULL pointer. If it is not NULL, then all entries in -** the sqlite_stat1 and (if applicable) sqlite_stat4 tables associated -** with the named table are deleted. If zWhere==0, then code is generated -** to delete all stat table entries. +** the sqlite_statN tables associated with the named table are deleted. +** If zWhere==0, then code is generated to delete all stat table entries. */ static void openStatTable( Parse *pParse, /* Parsing context */ @@ -188,16 +190,18 @@ static void openStatTable( #elif defined(SQLITE_ENABLE_STAT3) { "sqlite_stat3", "tbl,idx,neq,nlt,ndlt,sample" }, { "sqlite_stat4", 0 }, +#else + { "sqlite_stat3", 0 }, + { "sqlite_stat4", 0 }, #endif }; - - int aRoot[] = {0, 0}; - u8 aCreateTbl[] = {0, 0}; - int i; sqlite3 *db = pParse->db; Db *pDb; Vdbe *v = sqlite3GetVdbe(pParse); + int aRoot[ArraySize(aTable)]; + u8 aCreateTbl[ArraySize(aTable)]; + if( v==0 ) return; assert( sqlite3BtreeHoldsAllMutexes(db) ); assert( sqlite3VdbeDb(v)==db ); @@ -211,7 +215,7 @@ static void openStatTable( Table *pStat; if( (pStat = sqlite3FindTable(db, zTab, pDb->zName))==0 ){ if( aTable[i].zCols ){ - /* The sqlite_stat[12] table does not exist. Create it. Note that a + /* The sqlite_statN table does not exist. Create it. Note that a ** side-effect of the CREATE TABLE statement is to leave the rootpage ** of the new table in register pParse->regRoot. This is important ** because the OpenWrite opcode below will be needing it. */ @@ -226,6 +230,7 @@ static void openStatTable( ** associated with the table zWhere. If zWhere is NULL, delete the ** entire contents of the table. */ aRoot[i] = pStat->tnum; + aCreateTbl[i] = 0; sqlite3TableLock(pParse, iDb, aRoot[i], 1, zTab); if( zWhere ){ sqlite3NestedParse(pParse, @@ -239,11 +244,14 @@ static void openStatTable( } /* Open the sqlite_stat[134] tables for writing. */ - for(i=0; iaSample[] */ +#ifdef SQLITE_ENABLE_STAT34 + int mxSample = SQLITE_STAT4_SAMPLES; +#endif /* Decode the three function arguments */ UNUSED_PARAMETER(argc); - nRow = (tRowcnt)sqlite3_value_int64(argv[0]); - mxSample = SQLITE_STAT4_SAMPLES; - nCol = sqlite3_value_int(argv[1]); + nCol = sqlite3_value_int(argv[0]); assert( nCol>1 ); /* >1 because it includes the rowid column */ + nColUp = sizeof(tRowcnt)<8 ? (nCol+1)&~1 : nCol; /* Allocate the space required for the Stat4Accum object */ n = sizeof(*p) - + sizeof(tRowcnt)*nCol /* Stat4Accum.anEq */ - + sizeof(tRowcnt)*nCol /* Stat4Accum.anLt */ - + sizeof(tRowcnt)*nCol /* Stat4Accum.anDLt */ - + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */ - + sizeof(tRowcnt)*3*nCol*(nCol+mxSample); + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anEq */ + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anDLt */ +#ifdef SQLITE_ENABLE_STAT34 + + sizeof(tRowcnt)*nColUp /* Stat4Accum.anLt */ + + sizeof(Stat4Sample)*(nCol+mxSample) /* Stat4Accum.aBest[], a[] */ + + sizeof(tRowcnt)*3*nColUp*(nCol+mxSample) +#endif + ; p = sqlite3MallocZero(n); if( p==0 ){ sqlite3_result_error_nomem(context); return; } - p->nRow = nRow; + p->nRow = 0; p->nCol = nCol; - p->mxSample = mxSample; - p->nPSample = p->nRow/(mxSample/3+1) + 1; - p->iGet = -1; - p->current.anDLt = (tRowcnt*)&p[1]; - p->current.anEq = &p->current.anDLt[nCol]; - p->current.anLt = &p->current.anEq[nCol]; - sqlite3_randomness(sizeof(p->iPrn), &p->iPrn); - - /* Set up the Stat4Accum.a[] and aBest[] arrays */ - p->a = (struct Stat4Sample*)&p->current.anLt[nCol]; - p->aBest = &p->a[mxSample]; - pSpace = (u8*)(&p->a[mxSample+nCol]); - for(i=0; i<(mxSample+nCol); i++){ - p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nCol); - p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nCol); - p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nCol); - } - assert( (pSpace - (u8*)p)==n ); + p->current.anEq = &p->current.anDLt[nColUp]; - for(i=0; iaBest[i].iCol = i; +#ifdef SQLITE_ENABLE_STAT34 + { + u8 *pSpace; /* Allocated space not yet assigned */ + int i; /* Used to iterate through p->aSample[] */ + + p->iGet = -1; + p->mxSample = mxSample; + p->nPSample = sqlite3_value_int64(argv[1])/(mxSample/3+1) + 1; + p->current.anLt = &p->current.anEq[nColUp]; + sqlite3_randomness(sizeof(p->iPrn), &p->iPrn); + + /* Set up the Stat4Accum.a[] and aBest[] arrays */ + p->a = (struct Stat4Sample*)&p->current.anLt[nColUp]; + p->aBest = &p->a[mxSample]; + pSpace = (u8*)(&p->a[mxSample+nCol]); + for(i=0; i<(mxSample+nCol); i++){ + p->a[i].anEq = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); + p->a[i].anLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); + p->a[i].anDLt = (tRowcnt *)pSpace; pSpace += (sizeof(tRowcnt) * nColUp); + } + assert( (pSpace - (u8*)p)==n ); + + for(i=0; iaBest[i].iCol = i; + } } +#endif /* Return a pointer to the allocated object to the caller */ sqlite3_result_blob(context, p, sizeof(p), sqlite3_free); } static const FuncDef statInitFuncdef = { - 2, /* nArg */ + 1+IsStat34, /* nArg */ SQLITE_UTF8, /* iPrefEnc */ 0, /* flags */ 0, /* pUserData */ @@ -544,11 +563,16 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){ } /* -** Implementation of the stat_push SQL function. +** Implementation of the stat_push SQL function: stat_push(P,R,C) +** Arguments: +** +** P Pointer to the Stat4Accum object created by stat_init() +** C Index of left-most column to differ from previous row +** R Rowid for the current row ** -** stat_push(P,R,C) +** The SQL function always returns NULL. ** -** The return value is always NULL. +** The R parameter is only used for STAT3 and STAT4. */ static void statPush( sqlite3_context *context, @@ -559,15 +583,17 @@ static void statPush( /* The three function arguments */ Stat4Accum *p = (Stat4Accum*)sqlite3_value_blob(argv[0]); - i64 rowid = sqlite3_value_int64(argv[1]); - int iChng = sqlite3_value_int(argv[2]); + int iChng = sqlite3_value_int(argv[1]); assert( p->nCol>1 ); /* Includes rowid field */ assert( iChngnCol ); - /* p->current.anEq[0] is false the first time this function is called. */ - if( p->current.anEq[0] ){ - + if( p->nRow==0 ){ + /* anEq[0] is only zero for the very first call to this function. Do + ** appropriate initialization */ + for(i=0; inCol; i++) p->current.anEq[i] = 1; + }else{ + /* Second and subsequent calls get processed here */ samplePushPrevious(p, iChng); /* Update anDLt[], anLt[] and anEq[] to reflect the values that apply @@ -577,18 +603,17 @@ static void statPush( } for(i=iChng; inCol; i++){ p->current.anDLt[i]++; +#ifdef SQLITE_ENABLE_STAT34 p->current.anLt[i] += p->current.anEq[i]; +#endif p->current.anEq[i] = 1; } - - }else{ - for(i=0; inCol; i++) p->current.anEq[i] = 1; - } - - if( IsStat4 || IsStat3 ){ - p->current.iRowid = rowid; - p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345; } + p->nRow++; +#ifdef SQLITE_ENABLE_STAT34 + p->current.iRowid = sqlite3_value_int64(argv[2]); + p->current.iHash = p->iPrn = p->iPrn*1103515245 + 12345; +#endif #ifdef SQLITE_ENABLE_STAT4 { @@ -613,7 +638,7 @@ static void statPush( #endif } static const FuncDef statPushFuncdef = { - 3, /* nArg */ + 2+IsStat34, /* nArg */ SQLITE_UTF8, /* iPrefEnc */ 0, /* flags */ 0, /* pUserData */ @@ -749,7 +774,7 @@ static void statGet( #endif /* SQLITE_ENABLE_STAT34 */ } static const FuncDef statGetFuncdef = { - 2, /* nArg */ + 1+IsStat34, /* nArg */ SQLITE_UTF8, /* iPrefEnc */ 0, /* flags */ 0, /* pUserData */ @@ -771,7 +796,7 @@ static void callStatGet(Vdbe *v, int regStat4, int iParam, int regOut){ #endif sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4, regOut); sqlite3VdbeChangeP4(v, -1, (char*)&statGetFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 1 + IsStat3 + IsStat4); + sqlite3VdbeChangeP5(v, 1 + IsStat34); } /* @@ -797,8 +822,10 @@ static void analyzeOneTable( u8 needTableCnt = 1; /* True to count the table */ int regNewRowid = iMem++; /* Rowid for the inserted record */ int regStat4 = iMem++; /* Register to hold Stat4Accum object */ - int regRowid = iMem++; /* Rowid argument passed to stat_push() */ int regChng = iMem++; /* Index of changed index field */ +#ifdef SQLITE_ENABLE_STAT34 + int regRowid = iMem++; /* Rowid argument passed to stat_push() */ +#endif int regTemp = iMem++; /* Temporary use register */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ @@ -884,7 +911,7 @@ static void analyzeOneTable( ** ** chng_addr_N: ** regRowid = idx(rowid) - ** stat_push(P, regRowid, regChng) + ** stat_push(P, regChng, regRowid) ** Next csr ** if !eof(csr) goto next_row; ** @@ -905,15 +932,18 @@ static void analyzeOneTable( /* Invoke the stat_init() function. The arguments are: ** - ** * the number of rows in the index, - ** * the number of columns in the index including the rowid, - ** * the recommended number of samples for the stat3/stat4 table. + ** (1) the number of columns in the index including the rowid, + ** (2) the number of rows in the index, + ** + ** The second argument is only used for STAT3 and STAT4 */ - sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+1); - sqlite3VdbeAddOp2(v, OP_Integer, nCol+1, regStat4+2); +#ifdef SQLITE_ENABLE_STAT34 + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regStat4+2); +#endif + sqlite3VdbeAddOp2(v, OP_Integer, nCol+1, regStat4+1); sqlite3VdbeAddOp3(v, OP_Function, 0, regStat4+1, regStat4); sqlite3VdbeChangeP4(v, -1, (char*)&statInitFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 2); + sqlite3VdbeChangeP5(v, 1+IsStat34); /* Implementation of the following: ** @@ -964,17 +994,20 @@ static void analyzeOneTable( /* ** chng_addr_N: - ** regRowid = idx(rowid) - ** stat_push(P, regRowid, regChng) + ** regRowid = idx(rowid) // STAT34 only + ** stat_push(P, regChng, regRowid) // 3rd parameter STAT34 only ** Next csr ** if !eof(csr) goto next_row; */ sqlite3VdbeJumpHere(v, aGotoChng[nCol]); +#ifdef SQLITE_ENABLE_STAT34 sqlite3VdbeAddOp2(v, OP_IdxRowid, iIdxCur, regRowid); + assert( regRowid==(regStat4+2) ); +#endif + assert( regChng==(regStat4+1) ); sqlite3VdbeAddOp3(v, OP_Function, 1, regStat4, regTemp); sqlite3VdbeChangeP4(v, -1, (char*)&statPushFuncdef, P4_FUNCDEF); - sqlite3VdbeChangeP5(v, 3); - assert( regRowid==(regStat4+1) && regChng==(regStat4+2) ); + sqlite3VdbeChangeP5(v, 2+IsStat34); sqlite3VdbeAddOp2(v, OP_Next, iIdxCur, addrNextRow); /* Add the entry to the stat1 table. */ @@ -985,7 +1018,8 @@ static void analyzeOneTable( sqlite3VdbeChangeP5(v, OPFLAG_APPEND); /* Add the entries to the stat3 or stat4 table. */ - if( IsStat3 || IsStat4 ){ +#ifdef SQLITE_ENABLE_STAT34 + { int regEq = regStat1; int regLt = regStat1+1; int regDLt = regStat1+2; @@ -1004,25 +1038,25 @@ static void analyzeOneTable( callStatGet(v, regStat4, STAT_GET_NLT, regLt); callStatGet(v, regStat4, STAT_GET_NDLT, regDLt); sqlite3VdbeAddOp3(v, OP_NotExists, iTabCur, addrNext, regSampleRowid); - if( IsStat3 ){ - int iCol = pIdx->aiColumn[0]; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regSample); - }else{ - for(i=0; iaiColumn[i]; - sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i); - } - sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol+1, regSample); +#ifdef SQLITE_ENABLE_STAT3 + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, + pIdx->aiColumn[0], regSample); +#else + for(i=0; iaiColumn[i]; + sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, iCol, regCol+i); } - + sqlite3VdbeAddOp3(v, OP_MakeRecord, regCol, nCol+1, regSample); +#endif sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 6, regTemp, "bbbbbb", 0); sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur+1, regNewRowid); sqlite3VdbeAddOp3(v, OP_Insert, iStatCur+1, regTemp, regNewRowid); sqlite3VdbeAddOp2(v, OP_Goto, 0, addrNext); sqlite3VdbeJumpHere(v, addrIsNull); } +#endif /* SQLITE_ENABLE_STAT34 */ - /* Jump here if the index is empty */ + /* End of analysis */ sqlite3VdbeJumpHere(v, addrRewind); sqlite3DbFree(db, aGotoChng); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d705bd7500..47d085ca93 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3056,7 +3056,6 @@ extern int sqlite3PendingByte; void sqlite3RootPageMoved(sqlite3*, int, int, int); void sqlite3Reindex(Parse*, Token*, Token*); void sqlite3AlterFunctions(void); -void sqlite3AnalyzeFunctions(void); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); int sqlite3GetToken(const unsigned char *, int *); void sqlite3NestedParse(Parse*, const char*, ...); @@ -3107,8 +3106,11 @@ Expr *sqlite3CreateColumnExpr(sqlite3 *, SrcList *, int, int); void sqlite3BackupRestart(sqlite3_backup *); void sqlite3BackupUpdate(sqlite3_backup *, Pgno, const u8 *); +#if defined(SQLITE_ENABLE_STAT3) || defined(SQLITE_ENABLE_STAT4) +void sqlite3AnalyzeFunctions(void); int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*); void sqlite3Stat4ProbeFree(UnpackedRecord*); +#endif /* ** The interface to the LEMON-generated parser