]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
In the analyze_as_needed pragma, avoid running unnecessary OP_LoadAnalysis
authordrh <drh@noemail.net>
Sat, 18 Feb 2017 02:19:02 +0000 (02:19 +0000)
committerdrh <drh@noemail.net>
Sat, 18 Feb 2017 02:19:02 +0000 (02:19 +0000)
and OP_Expire opcodes.  Make the analyze_as_needed pragma responsive to the
schema name.

FossilOrigin-Name: 882599a4a7ea92c9e7752e0745475508e58a11c3

manifest
manifest.uuid
src/analyze.c
src/parse.y
src/pragma.c
src/sqliteInt.h

index 42a11a725c8e02a1350a6ab0f5a659ecd9a0a3bd..d311cdbbf35796152b97f1da5cb73150e1df86a8 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sanalyze_as_needed\spragma\snow\sresponds\sto\stable\ssize\sgrowth\sand\swill\nautomatically\srerun\sthe\sanalysis\safter\seach\s10x\ssize\sincrease.
-D 2017-02-17T19:24:06.618
+C In\sthe\sanalyze_as_needed\spragma,\savoid\srunning\sunnecessary\sOP_LoadAnalysis\s\nand\sOP_Expire\sopcodes.\s\sMake\sthe\sanalyze_as_needed\spragma\sresponsive\sto\sthe\nschema\sname.
+D 2017-02-18T02:19:02.183
 F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2
@@ -331,7 +331,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b
 F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786
 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a
 F src/alter.c 3b23977620ce9662ac54443f65b87ba996e36121
-F src/analyze.c acef9c48eac30438e82f39eb8df6682c6e33942e
+F src/analyze.c eb50045b8f2e0d8a0a36a2158a65afe098d9a3bb
 F src/attach.c 8c476f8bd5d2afe11d925f890d30e527e5b0ce43
 F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
 F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
@@ -383,11 +383,11 @@ F src/os_win.c cf90abd4e50d9f56d2c20ce8e005aff55d7bd8e9
 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
 F src/pager.c ff1232b3088a39806035ecfac4fffeb22717d80b
 F src/pager.h f2a99646c5533ffe11afa43e9e0bea74054e4efa
-F src/parse.y d5695ae4887a52352b1b8a3e3623477c7e79abeb
+F src/parse.y 591704fce84f814d9a3642774c1f011d38f4149c
 F src/pcache.c 62835bed959e2914edd26afadfecce29ece0e870
 F src/pcache.h 2cedcd8407eb23017d92790b112186886e179490
 F src/pcache1.c e3967219b2a92b9edcb9324a4ba75009090d3953
-F src/pragma.c e8b2ea66dfb1b90c53b920c08914ac26b109053a
+F src/pragma.c cf0f101d2986d258699cbbd249392858ec9a6b7e
 F src/pragma.h 065e184494f12e94111da1ab6984faa7b6142e68
 F src/prepare.c b1140c3d0cf59bc85ace00ce363153041b424b7a
 F src/printf.c 67427bbee66d891fc6f6f5aada857e9cdb368c1c
@@ -399,7 +399,7 @@ F src/shell.c bb8e20789499aec921a01d8744c616b81b8214f1
 F src/sqlite.h.in 751ff125eb159c8f92c182b8df980a5e4f50e966
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h 8648034aa702469afb553231677306cc6492a1ae
-F src/sqliteInt.h 60c38b84a796cc9d0a9a794cca254b09898b9cc5
+F src/sqliteInt.h 70abfa92e02688f1d189bf63fd25d309ca8d8d1e
 F src/sqliteLimit.h c0373387c287c8d0932510b5547ecde31b5da247
 F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@@ -1557,7 +1557,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P e93db2373127d31d33ec46ef918fa9386bb664a6
-R 484e61dbf95be1098adb3acfa069e723
+P bfbdd07409688fac4ccddbab3639745f6152e23d
+R 1c1b7451b307830f90322e6d51007af7
 U drh
-Z 81466028927592a195c5763d3460fcde
+Z 2d7c806c83a06bb426974433c00a5916
index 8be7eeb5b943d64607ac825ff7516c27f863152d..9825130b6a209221fabcf49d5f9e86e522fd78a9 100644 (file)
@@ -1 +1 @@
-bfbdd07409688fac4ccddbab3639745f6152e23d
\ No newline at end of file
+882599a4a7ea92c9e7752e0745475508e58a11c3
\ No newline at end of file
index 082713fd23a4ddad6a8c3e85cb8b92e355c2d174..c30027aec9581fb31e6f875b37e0db81867c2444 100644 (file)
@@ -971,6 +971,7 @@ static void analyzeOneTable(
   int jZeroRows = -1;          /* Jump from here if number of rows is zero */
   int iDb;                     /* Index of database containing pTab */
   u8 needTableCnt = 1;         /* True to count the table */
+  int regWorkDone = iMem++;    /* Set to 1 if any work is done */
   int regNewRowid = iMem++;    /* Rowid for the inserted record */
   int regStat4 = iMem++;       /* Register to hold Stat4Accum object */
   int regChng = iMem++;        /* Index of changed index field */
@@ -1018,7 +1019,7 @@ static void analyzeOneTable(
   sqlite3OpenTable(pParse, iTabCur, iDb, pTab, OP_OpenRead);
   if( szOld>0 ){
     addrSizeCk = sqlite3VdbeAddOp3(v, OP_IfSmaller, iTabCur, 0, szOld);
-   }
+  }
   sqlite3VdbeLoadString(v, regTabname, pTab->zName);
 
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
@@ -1276,21 +1277,11 @@ static void analyzeOneTable(
     sqlite3VdbeChangeP5(v, OPFLAG_APPEND);
     sqlite3VdbeJumpHere(v, jZeroRows);
   }
+  sqlite3VdbeAddOp2(v, OP_Integer, 1, regWorkDone);
+  VdbeComment((v, "work was done"));
   sqlite3VdbeJumpHere(v, addrSizeCk);
 }
 
-
-/*
-** Generate code that will cause the most recent index analysis to
-** be loaded into internal hash tables where is can be used.
-*/
-static void loadAnalysis(Parse *pParse, int iDb){
-  Vdbe *v = sqlite3GetVdbe(pParse);
-  if( v ){
-    sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb);
-  }
-}
-
 /*
 ** Return true if table pTab might need to being reanalyzed.  Return
 ** false if we know that pTab should not be reanalyzed.
@@ -1322,54 +1313,70 @@ static int analyzeNeeded(Table *pTab, LogEst *pThreshold){
 }
 
 /*
-** Generate code that will do an analysis of an entire database.
+** Generate code that will do an analysis of an entire database, or
+** all databases in the connection if iDbReq is negative.
 **
-** Return a count of the number of tables actually analyzed.  Return 0
-** if nothing was analyzed.
+** If onlyIfNeeded is true, then only run the analysis if SQLite thinks
+** it is actually needed.
 */
-static int analyzeDatabase(Parse *pParse, int iDbReq, int onlyIfNeeded){
+void sqlite3AnalyzeDatabase(
+  Parse *pParse,       /* The parsing context */
+  int iDbReq,          /* Which schema to analyze. -1 for all (except TEMP) */
+  int onlyIfNeeded     /* Only do the analysis if needed, when true */
+){
   sqlite3 *db = pParse->db;
   Schema *pSchema;
   HashElem *k;
-  int iStatCur;
-  int iMem;
-  int iTab;
+  int iStatCur = 0;
+  int iMem = 0;
+  int iTab = 0;
   int iDb;                /* Database currently being analyzed */
   int iDbFirst, iDbLast;  /* Range of databases to be analyzed */
-  int cnt;                /* Number of tables analyzed in a single database */
-  int allCnt = 0;         /* Number of tables analyzed across all databases */
+  int bStatTabs = 0;
+  Vdbe *v = sqlite3GetVdbe(pParse);
+  int nHit = 0;
+  unsigned char aHit[SQLITE_MAX_ATTACHED+2];
 
+  if( v==0 ) return;
   if( iDbReq>=0 ){
     iDbFirst = iDbLast = iDbReq;
   }else{
     iDbFirst = 0;
     iDbLast = db->nDb-1;
   }
-  for(iDb=iDbFirst; iDb<=iDbLast; iDb++){
+  for(iDb=iDbFirst; iDb<=iDbLast; iDb++, bStatTabs=0){
     if( iDb==1 ) continue;  /* Do not analyze the TEMP database */
     pSchema = db->aDb[iDb].pSchema;
     assert( sqlite3SchemaMutexHeld(db, iDb, 0) );
-    cnt = 0;
     for(k=sqliteHashFirst(&pSchema->tblHash); k; k=sqliteHashNext(k)){
       Table *pTab = (Table*)sqliteHashData(k);
       LogEst szThreshold = 0;
       if( !onlyIfNeeded || analyzeNeeded(pTab, &szThreshold) ){
-        if( cnt==0 ){
-          sqlite3BeginWriteOperation(pParse, 0, iDb);
+        if( iMem==0 ){
           iStatCur = pParse->nTab;
           pParse->nTab += 3;
-          openStatTable(pParse, iDb, iStatCur, 0, 0);
           iMem = pParse->nMem+1;
           iTab = pParse->nTab;
+          sqlite3VdbeAddOp2(v, OP_Integer, 0, iMem);
+        }
+        if( !bStatTabs ){
+          aHit[nHit++] = iDb;
+          sqlite3BeginWriteOperation(pParse, 0, iDb);
+          openStatTable(pParse, iDb, iStatCur, 0, 0);
+          bStatTabs = 1;
         }
         analyzeOneTable(pParse, pTab, 0, iStatCur, iMem, iTab, szThreshold);
-        cnt++;
-        allCnt++;
       }
     }
-    if( cnt ) loadAnalysis(pParse, iDb);
   }
-  return allCnt;
+  if( iMem ){
+    int addrTop = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); VdbeCoverage(v);
+    for(iDb=0; iDb<nHit; iDb++){
+      sqlite3VdbeAddOp1(v, OP_LoadAnalysis, aHit[iDb]);
+    }
+    sqlite3VdbeAddOp0(v, OP_Expire);
+    sqlite3VdbeJumpHere(v, addrTop);
+  }
 }
 
 /*
@@ -1380,6 +1387,7 @@ static int analyzeDatabase(Parse *pParse, int iDbReq, int onlyIfNeeded){
 static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
   int iDb;
   int iStatCur;
+  Vdbe *v;
 
   assert( pTab!=0 );
   assert( sqlite3BtreeHoldsAllMutexes(pParse->db) );
@@ -1392,9 +1400,13 @@ static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
   }else{
     openStatTable(pParse, iDb, iStatCur, pTab->zName, "tbl");
   }
-  analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur,pParse->nMem+1,
+  analyzeOneTable(pParse, pTab, pOnlyIdx, iStatCur, pParse->nMem+1,
                   pParse->nTab, 0);
-  loadAnalysis(pParse, iDb);
+  v = sqlite3GetVdbe(pParse);
+  if( v ){
+    sqlite3VdbeAddOp1(v, OP_LoadAnalysis, iDb);
+    sqlite3VdbeAddOp0(v, OP_Expire);
+  }
 }
 
 /*
@@ -1414,15 +1426,13 @@ static void analyzeTable(Parse *pParse, Table *pTab, Index *pOnlyIdx){
 ** are believed to be in need of analysis.  The conditional analysis
 ** might well be a no-op.
 */
-void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2, int ifNeeded){
+void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2){
   sqlite3 *db = pParse->db;
   int iDb;
   char *z, *zDb;
   Table *pTab;
   Index *pIdx;
   Token *pTableName;
-  Vdbe *v;
-  int needExpire = 1;
 
   /* Read the database schema. If an error occurs, leave an error message
   ** and code in pParse and return NULL. */
@@ -1434,12 +1444,12 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2, int ifNeeded){
   assert( pName2!=0 || pName1==0 );
   if( pName1==0 ){
     /* Form 1:  Analyze everything */
-    needExpire = analyzeDatabase(pParse, -1, ifNeeded) || ifNeeded==0;
+    sqlite3AnalyzeDatabase(pParse, -1, 0);
   }else if( pName2->n==0 ){
     /* Form 2:  Analyze the database or table named */
     iDb = sqlite3FindDb(db, pName1);
     if( iDb>=0 ){
-      analyzeDatabase(pParse, iDb, 0);
+      sqlite3AnalyzeDatabase(pParse, iDb, 0);
     }else{
       z = sqlite3NameFromToken(db, pName1);
       if( z ){
@@ -1467,10 +1477,6 @@ void sqlite3Analyze(Parse *pParse, Token *pName1, Token *pName2, int ifNeeded){
       }
     }   
   }
-  if( needExpire ){
-    v = sqlite3GetVdbe(pParse);
-    if( v ) sqlite3VdbeAddOp0(v, OP_Expire);
-  }
 }
 
 /*
index ff03c128ace465d372dee460eb98878df2117355..9cada2a1be46731d055a770d87c9912112f556a3 100644 (file)
@@ -1512,8 +1512,8 @@ cmd ::= REINDEX nm(X) dbnm(Y).  {sqlite3Reindex(pParse, &X, &Y);}
 
 /////////////////////////////////// ANALYZE ///////////////////////////////////
 %ifndef SQLITE_OMIT_ANALYZE
-cmd ::= ANALYZE.                {sqlite3Analyze(pParse, 0, 0, 0);}
-cmd ::= ANALYZE nm(X) dbnm(Y).  {sqlite3Analyze(pParse, &X, &Y, 0);}
+cmd ::= ANALYZE.                {sqlite3Analyze(pParse, 0, 0);}
+cmd ::= ANALYZE nm(X) dbnm(Y).  {sqlite3Analyze(pParse, &X, &Y);}
 %endif
 
 //////////////////////// ALTER TABLE table ... ////////////////////////////////
index 789751958c06b541df4a36e0cb4407e4ca37fcd7..3bcf62f69fe7b60e058c152ee09b288b5d2b7059 100644 (file)
@@ -1832,7 +1832,7 @@ void sqlite3Pragma(
   **  PRAGMA analyze_as_needed
   */
   case PragTyp_ANALYZE_AS_NEEDED: {
-    sqlite3Analyze(pParse, 0, 0, 1);
+    sqlite3AnalyzeDatabase(pParse, zDb ? iDb : -1, 1);
     break;
   }
 
index d9cad11bcfade79716d55e6ddcbed95f01ddcbc9..218c2c6af6c853d5b20524b7e796633068203daa 100644 (file)
@@ -4027,7 +4027,8 @@ void sqlite3AlterFinishAddColumn(Parse *, Token *);
 void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
 CollSeq *sqlite3GetCollSeq(Parse*, u8, CollSeq *, const char*);
 char sqlite3AffinityType(const char*, u8*);
-void sqlite3Analyze(Parse*, Token*, Token*, int);
+void sqlite3Analyze(Parse*, Token*, Token*);
+void sqlite3AnalyzeDatabase(Parse*,int,int);
 int sqlite3InvokeBusyHandler(BusyHandler*);
 int sqlite3FindDb(sqlite3*, Token*);
 int sqlite3FindDbName(sqlite3 *, const char *);