diff --git a/manifest b/manifest index 6ade0dd8d2..b3ebf022c3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,8 @@ -C Add\snew\sfile\se_createtable.test. -D 2010-09-25T17:29:58 +-----BEGIN PGP SIGNED MESSAGE----- +Hash: SHA1 + +C Enhance\sthe\sANALYZE\scommand\sso\sthat\sit\sgathers\sstatistics\sin\sthe\ssqlite_stat1\ntable\seven\sfor\stables\sthat\sare\sempty\sor\shave\sno\sindices. +D 2010-09-25T22:32:56 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in c599a15d268b1db2aeadea19df2adc3bf2eb6bee F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -112,7 +115,7 @@ F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 6be1ad09113570e1fc8dcaff84c9b0b337db5ffc F sqlite3.pc.in ae6f59a76e862f5c561eb32a380228a02afc3cad F src/alter.c 8dc27638e7e2553e80b2b621f232be5eb1e85ef3 -F src/analyze.c da65ce99bb159b10e85a1e460adbe53a88062500 +F src/analyze.c df69779a9bad368de5f5a32b8c733282d8dcbbbe F src/attach.c c689d516ee8cc52bf11bef2067d76eb8b716228a F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c d5b0137bc20327af08c14772227cc35134839c30 @@ -121,7 +124,7 @@ F src/btmutex.c 96a12f50f7a17475155971a241d85ec5171573ff F src/btree.c d878577184112d982d00ea05afcc7487cd9f06f5 F src/btree.h 2d1a83ad509047e8cc314fda7e054f99ff52414d F src/btreeInt.h c424f2f131cc61ddf130f9bd736b3df12c8a51f0 -F src/build.c 5acc8a7d79ca81102a5d020fbafb7a4162f96d1d +F src/build.c 99894b89b7943b6f8337757facc4e61cef1d9508 F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df @@ -177,7 +180,7 @@ F src/select.c b0b124781474e4e0c8f64022875e5e2009e13443 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056 F src/sqlite.h.in dae3f74d7b2b516967ede39b8e503718b571d9da F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89 -F src/sqliteInt.h ef7ed8746759c09edd87e5550de973a4da3e4ca7 +F src/sqliteInt.h d8ae67308fec3f2abdce817a630aceae42ad8043 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44 F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e @@ -237,7 +240,7 @@ F src/vtab.c 0e8e0cb30dffb078367e843e84e37ef99236c7e4 F src/wal.c 7081f148cb52b0cf2280e6384196402dc58130a3 F src/wal.h 96669b645e27cd5a111ba59f0cae7743a207bc3c F src/walker.c 3112bb3afe1d85dc52317cb1d752055e9a781f8f -F src/where.c a5040c004496d456761e8f10750f648bbd84e982 +F src/where.c 34c733f9e8ca5e8f611958422e7cc236bc9cf739 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/alias.test 4529fbc152f190268a15f9384a5651bbbabc9d87 F test/all.test 6745008c144bd2956d58864d21f7b304689c1cce @@ -246,7 +249,7 @@ F test/alter2.test 75f731508f1bf27ba09a6075c66cd02216ba464b F test/alter3.test 8677e48d95536f7a6ed86a1a774744dadcc22b07 F test/alter4.test 1e5dd6b951e9f65ca66422edff02e56df82dd403 F test/altermalloc.test e81ac9657ed25c6c5bb09bebfa5a047cd8e4acfc -F test/analyze.test bf692e7db414f268a136bade16c03a1bdbb9240c +F test/analyze.test c1eb87067fc16ece7c07e823d6395fd831b270c5 F test/analyze2.test 59dac6c399c0c5d1a90a11ee7cc606743fb6db93 F test/analyze3.test 6d4f4b0929545a9d1af803a0608a0c51b92a3537 F test/async.test ad4ba51b77cd118911a3fe1356b0809da9c108c3 @@ -258,7 +261,7 @@ F test/attach.test ce9660e51768fab93cf129787be886c5d6c4fd81 F test/attach2.test a295d2d7061adcee5884ef4a93c7c96a82765437 F test/attach3.test bd9830bc3a0d22ed1310c9bff6896927937017dc F test/attachmalloc.test 38d2da5fdaf09ba0add57296967a3061e5842584 -F test/auth.test 8f21c160a4562f54f27618e85bac869efcecbcaf +F test/auth.test 26cc6f219580191539bf335abe03e55e49310846 F test/auth2.test 270baddc8b9c273682760cffba6739d907bd2882 F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/autoinc.test 85ef3180a737e6580086a018c09c6f1a52759b46 @@ -543,7 +546,7 @@ F test/minmax3.test 66a60eb0f20281b0753249d347c5de0766954cee F test/misc1.test e56baf44656dd68d6475a4b44521045a60241e9b F test/misc2.test a628db7b03e18973e5d446c67696b03de718c9fd F test/misc3.test 72c5dc87a78e7865c5ec7a969fc572913dbe96b6 -F test/misc4.test 91e8ed25c092c2bb4e0bb01864631e2930f8d7de +F test/misc4.test 9c078510fbfff05a9869a0b6d8b86a623ad2c4f6 F test/misc5.test 45b2e3ed5f79af2b4f38ae362eaf4c49674575bd F test/misc6.test 953cc693924d88e6117aeba16f46f0bf5abede91 F test/misc7.test c5f4e6a82e04e71820c0f9f64f6733f04c8ae0ae @@ -600,7 +603,7 @@ F test/select2.test 352480e0e9c66eda9c3044e412abdf5be0215b56 F test/select3.test 2ce595f8fb8e2ac10071d3b4e424cadd4634a054 F test/select4.test 44aa6e7110592e18110b0b9cf5c024d37d23be17 F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 -F test/select6.test 2b5e8500d8ec3dd4c8e0c99eb1431b3d11fcc24c +F test/select6.test cc25a8650cf9a4d4f74e586c45a75f9836516b18 F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d F test/select9.test 74c0fb2c6eecb0219cbed0cbe3df136f8fbf9343 @@ -736,7 +739,7 @@ F test/tkt35xx.test ed9721bd9eb1693b3b4d3cf2a093fa7f92af0c93 F test/tkt3630.test 929f64852103054125200bc825c316d5f75d42f7 F test/tkt3718.test 3b59dcb5c4e7754dacd91e7fd353a61492cc402a F test/tkt3731.test 0c5f4cbffe102d43c3b2188af91a9e36348f974b -F test/tkt3757.test 8f2208930655bbd4f92c14e19e72303a43e098ef +F test/tkt3757.test 10cd679a88675c880533083fc79ac04324525595 F test/tkt3761.test b95ea9c98f21cf91325f18a984887e62caceab33 F test/tkt3762.test 2a9f3b03df44ec49ec0cfa8d5da6574c2a7853df F test/tkt3773.test 430b06567ce40285dfd2c4834a2a61816403efeb @@ -867,7 +870,14 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f -P 44deaaefeeb95827daeaf84aa5e205b456e75b40 -R f9cdaa74878a8325422c228d4f8c7dbc -U dan -Z 39756bc936cfb3dbb51046b9bdefa610 +P 20e16fef55c355a1d7e97d0c390769b941e83fdb +R 96b44d864f75b35f18ba4c7ab3226d4c +U drh +Z e1547e0aba5840882b569e70505d3edd +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQFMnnieoxKgR168RlERAs7CAJ9XFT8WTA9gYf6noiCftlq/XsWqugCfaGoh +P4TBzZ9lm4AFS3sK2f1UkgA= +=phK5 +-----END PGP SIGNATURE----- diff --git a/manifest.uuid b/manifest.uuid index 37263b39d6..1ebe527711 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -20e16fef55c355a1d7e97d0c390769b941e83fdb \ No newline at end of file +a7645d293801da64a7579737d0a8b48117af2e2c \ No newline at end of file diff --git a/src/analyze.c b/src/analyze.c index 59849456fc..4b4175fe4c 100644 --- a/src/analyze.c +++ b/src/analyze.c @@ -114,6 +114,7 @@ static void analyzeOneTable( int topOfLoop; /* The top of the loop */ int endOfLoop; /* The end of the loop */ int addr; /* The address of an instruction */ + int jZeroRows = 0; /* Jump from here if number of rows is zero */ int iDb; /* Index of database containing pTab */ int regTabname = iMem++; /* Register containing table name */ int regIdxname = iMem++; /* Register containing index name */ @@ -132,8 +133,15 @@ static void analyzeOneTable( #endif v = sqlite3GetVdbe(pParse); - if( v==0 || NEVER(pTab==0) || pTab->pIndex==0 ){ - /* Do no analysis for tables that have no indices */ + if( v==0 || NEVER(pTab==0) ){ + return; + } + if( pTab->pSelect ){ + /* Do not gather statistics on views */ + return; + } + if( memcmp(pTab->zName, "sqlite_", 7)==0 ){ + /* Do not gather statistics on system tables */ return; } assert( sqlite3BtreeHoldsAllMutexes(db) ); @@ -150,6 +158,7 @@ static void analyzeOneTable( sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); iIdxCur = pParse->nTab++; + sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ int nCol = pIdx->nColumn; KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx); @@ -164,10 +173,7 @@ static void analyzeOneTable( (char *)pKey, P4_KEYINFO_HANDOFF); VdbeComment((v, "%s", pIdx->zName)); - /* Populate the registers containing the table and index names. */ - if( pTab->pIndex==pIdx ){ - sqlite3VdbeAddOp4(v, OP_String8, 0, regTabname, 0, pTab->zName, 0); - } + /* Populate the register containing the index name. */ sqlite3VdbeAddOp4(v, OP_String8, 0, regIdxname, 0, pIdx->zName, 0); #ifdef SQLITE_ENABLE_STAT2 @@ -302,8 +308,10 @@ static void analyzeOneTable( ** If K>0 then it is always the case the D>0 so division by zero ** is never possible. */ - addr = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); sqlite3VdbeAddOp2(v, OP_SCopy, iMem, regSampleno); + if( jZeroRows==0 ){ + jZeroRows = sqlite3VdbeAddOp1(v, OP_IfNot, iMem); + } for(i=0; ipIndex==0 ){ + sqlite3VdbeAddOp3(v, OP_OpenRead, iIdxCur, pTab->tnum, iDb); + VdbeComment((v, "%s", pTab->zName)); + sqlite3VdbeAddOp2(v, OP_Count, iIdxCur, regSampleno); + sqlite3VdbeAddOp1(v, OP_Close, iIdxCur); + }else{ + assert( jZeroRows>0 ); + addr = sqlite3VdbeAddOp0(v, OP_Goto); + sqlite3VdbeJumpHere(v, jZeroRows); + } + sqlite3VdbeAddOp2(v, OP_Null, 0, regIdxname); + sqlite3VdbeAddOp4(v, OP_MakeRecord, regTabname, 3, regRec, "aaa", 0); + sqlite3VdbeAddOp2(v, OP_NewRowid, iStatCur, regRowid); + sqlite3VdbeAddOp3(v, OP_Insert, iStatCur, regRec, regRowid); + sqlite3VdbeChangeP5(v, OPFLAG_APPEND); + if( pParse->nMemnMem = regRec; + if( jZeroRows ){ sqlite3VdbeJumpHere(v, addr); } } /* ** Generate code that will cause the most recent index analysis to -** be laoded into internal hash tables where is can be used. +** be loaded into internal hash tables where is can be used. */ static void loadAnalysis(Parse *pParse, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); @@ -453,33 +483,46 @@ struct analysisInfo { ** This callback is invoked once for each index when reading the ** sqlite_stat1 table. ** -** argv[0] = name of the index -** argv[1] = results of analysis - on integer for each column +** argv[0] = name of the table +** argv[1] = name of the index (might be NULL) +** argv[2] = results of analysis - on integer for each column +** +** Entries for which argv[1]==NULL simply record the number of rows in +** the table. */ static int analysisLoader(void *pData, int argc, char **argv, char **NotUsed){ analysisInfo *pInfo = (analysisInfo*)pData; Index *pIndex; - int i, c; + Table *pTable; + int i, c, n; unsigned int v; const char *z; - assert( argc==2 ); + assert( argc==3 ); UNUSED_PARAMETER2(NotUsed, argc); - if( argv==0 || argv[0]==0 || argv[1]==0 ){ + if( argv==0 || argv[0]==0 || argv[2]==0 ){ return 0; } - pIndex = sqlite3FindIndex(pInfo->db, argv[0], pInfo->zDatabase); - if( pIndex==0 ){ + pTable = sqlite3FindTable(pInfo->db, argv[0], pInfo->zDatabase); + if( pTable==0 ){ return 0; } - z = argv[1]; - for(i=0; *z && i<=pIndex->nColumn; i++){ + if( argv[1] ){ + pIndex = sqlite3FindIndex(pInfo->db, argv[1], pInfo->zDatabase); + }else{ + pIndex = 0; + } + n = pIndex ? pIndex->nColumn : 0; + z = argv[2]; + for(i=0; *z && i<=n; i++){ v = 0; while( (c=z[0])>='0' && c<='9' ){ v = v*10 + c - '0'; z++; } + if( i==0 ) pTable->nRowEst = v; + if( pIndex==0 ) break; pIndex->aiRowEst[i] = v; if( *z==' ' ) z++; } @@ -555,7 +598,7 @@ int sqlite3AnalysisLoad(sqlite3 *db, int iDb){ /* Load new statistics out of the sqlite_stat1 table */ zSql = sqlite3MPrintf(db, - "SELECT idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase); + "SELECT tbl, idx, stat FROM %Q.sqlite_stat1", sInfo.zDatabase); if( zSql==0 ){ rc = SQLITE_NOMEM; }else{ diff --git a/src/build.c b/src/build.c index 6acab1ddee..ebd077ac5d 100644 --- a/src/build.c +++ b/src/build.c @@ -802,6 +802,7 @@ void sqlite3StartTable( pTable->iPKey = -1; pTable->pSchema = db->aDb[iDb].pSchema; pTable->nRef = 1; + pTable->nRowEst = 1000000; assert( pParse->pNewTable==0 ); pParse->pNewTable = pTable; @@ -2830,14 +2831,14 @@ exit_create_index: void sqlite3DefaultRowEst(Index *pIdx){ unsigned *a = pIdx->aiRowEst; int i; + unsigned n; assert( a!=0 ); - a[0] = 1000000; - for(i=pIdx->nColumn; i>=5; i--){ - a[i] = 5; - } - while( i>=1 ){ - a[i] = 11 - i; - i--; + a[0] = pIdx->pTable->nRowEst; + if( a[0]<10 ) a[0] = 10; + n = 10; + for(i=1; i<=pIdx->nColumn; i++){ + a[i] = n; + if( n>5 ) n--; } if( pIdx->onError!=OE_None ){ a[pIdx->nColumn] = 1; diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 3ebc90082c..cefc94e8d9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1252,6 +1252,7 @@ struct Table { Column *aCol; /* Information about each column */ Index *pIndex; /* List of SQL indexes on this table. */ int tnum; /* Root BTree node for this table (see note above) */ + unsigned nRowEst; /* Estimated rows in table - from sqlite_stat1 table */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ u16 nRef; /* Number of pointers to this Table */ u8 tabFlags; /* Mask of TF_* values */ diff --git a/src/where.c b/src/where.c index 8cc547066e..4ff77df7d8 100644 --- a/src/where.c +++ b/src/where.c @@ -1706,7 +1706,7 @@ static void bestAutomaticIndex( assert( pParse->nQueryLoop >= (double)1 ); pTable = pSrc->pTab; - nTableRow = pTable->pIndex ? pTable->pIndex->aiRowEst[0] : 1000000; + nTableRow = pTable->nRowEst; logN = estLog(nTableRow); costTempIdx = 2*logN*(nTableRow/pParse->nQueryLoop + 1); if( costTempIdx>=pCost->rCost ){ @@ -2513,23 +2513,14 @@ static void bestBtreeIndex( sPk.nColumn = 1; sPk.aiColumn = &aiColumnPk; sPk.aiRowEst = aiRowEstPk; - aiRowEstPk[1] = 1; sPk.onError = OE_Replace; sPk.pTable = pSrc->pTab; + aiRowEstPk[0] = pSrc->pTab->nRowEst; + aiRowEstPk[1] = 1; pFirst = pSrc->pTab->pIndex; if( pSrc->notIndexed==0 ){ sPk.pNext = pFirst; } - /* The aiRowEstPk[0] is an estimate of the total number of rows in the - ** table. Get this information from the ANALYZE information if it is - ** available. If not available, assume the table 1 million rows in size. - */ - if( pFirst ){ - assert( pFirst->aiRowEst!=0 ); /* Allocated together with pFirst */ - aiRowEstPk[0] = pFirst->aiRowEst[0]; - }else{ - aiRowEstPk[0] = 1000000; - } pProbe = &sPk; wsFlagMask = ~( WHERE_COLUMN_IN|WHERE_COLUMN_EQ|WHERE_COLUMN_NULL|WHERE_COLUMN_RANGE @@ -4103,7 +4094,7 @@ WhereInfo *sqlite3WhereBegin( ** ** The best strategy is to iterate through table t1 first. However it ** is not possible to determine this with a simple greedy algorithm. - ** However, since the cost of a linear scan through table t2 is the same + ** Since the cost of a linear scan through table t2 is the same ** as the cost of a linear scan through table t1, a simple greedy ** algorithm may choose to use t2 for the outer loop, which is a much ** costlier approach. diff --git a/test/analyze.test b/test/analyze.test index 5bd653a93b..177936c224 100644 --- a/test/analyze.test +++ b/test/analyze.test @@ -73,7 +73,7 @@ do_test analyze-1.6.3 { } {1 {table sqlite_stat1 may not be indexed}} do_test analyze-1.7 { execsql { - SELECT * FROM sqlite_stat1 + SELECT * FROM sqlite_stat1 WHERE idx NOT NULL } } {} do_test analyze-1.8 { @@ -83,7 +83,7 @@ do_test analyze-1.8 { } {0 {}} do_test analyze-1.9 { execsql { - SELECT * FROM sqlite_stat1 + SELECT * FROM sqlite_stat1 WHERE idx NOT NULL } } {} do_test analyze-1.10 { @@ -96,7 +96,7 @@ do_test analyze-1.11 { execsql { SELECT * FROM sqlite_stat1 } -} {} +} {t1 {} 0} do_test analyze-1.12 { catchsql { ANALYZE t1; @@ -106,7 +106,7 @@ do_test analyze-1.13 { execsql { SELECT * FROM sqlite_stat1 } -} {} +} {t1 {} 0} # Create some indices that can be analyzed. But do not yet add # data. Without data in the tables, no analysis is done. @@ -117,21 +117,21 @@ do_test analyze-2.1 { ANALYZE main.t1; SELECT * FROM sqlite_stat1 ORDER BY idx; } -} {} +} {t1 {} 0} do_test analyze-2.2 { execsql { CREATE INDEX t1i2 ON t1(b); ANALYZE t1; SELECT * FROM sqlite_stat1 ORDER BY idx; } -} {} +} {t1 {} 0} do_test analyze-2.3 { execsql { CREATE INDEX t1i3 ON t1(a,b); ANALYZE main; SELECT * FROM sqlite_stat1 ORDER BY idx; } -} {} +} {t1 {} 0} # Start adding data to the table. Verify that the analysis # is done correctly. diff --git a/test/auth.test b/test/auth.test index 8b7cae3e11..bb974ea3ee 100644 --- a/test/auth.test +++ b/test/auth.test @@ -1976,12 +1976,12 @@ ifcapable analyze { ANALYZE; } set ::authargs - } {t4 {} main {}} + } {t4 {} main {} t2 {} main {}} do_test auth-1.295 { execsql { SELECT count(*) FROM sqlite_stat1; } - } 2 + } 3 proc auth {code args} { if {$code=="SQLITE_ANALYZE"} { set ::authargs [concat $::authargs $args] @@ -1999,7 +1999,7 @@ ifcapable analyze { execsql { SELECT count(*) FROM sqlite_stat1; } - } 2 + } 3 } ;# ifcapable analyze diff --git a/test/misc4.test b/test/misc4.test index 026dd032e3..59c1d118ac 100644 --- a/test/misc4.test +++ b/test/misc4.test @@ -151,7 +151,7 @@ ifcapable subquery { select a.*, x.* from a, (select key,sum(period) from b group by key) as x - where a.key=x.key; + where a.key=x.key order by 1 desc; } } {01 data01 01 3 +1 data+1 +1 7} diff --git a/test/select6.test b/test/select6.test index ef0bfd5660..e0ff165c55 100644 --- a/test/select6.test +++ b/test/select6.test @@ -458,6 +458,7 @@ do_test select6-8.6 { do_test select6-9.1 { execsql { SELECT a.x, b.x FROM t1 AS a, (SELECT x FROM t1 LIMIT 2) AS b + ORDER BY 1, 2 } } {1 1 1 2 2 1 2 2 3 1 3 2 4 1 4 2} do_test select6-9.2 { diff --git a/test/tkt3757.test b/test/tkt3757.test index 14bfb23be7..011beb5c8b 100644 --- a/test/tkt3757.test +++ b/test/tkt3757.test @@ -35,9 +35,9 @@ do_test tkt3757-1.1 { CREATE TABLE t2(a INTEGER, b TEXT); INSERT INTO t2 VALUES(2, 'two'); ANALYZE; - SELECT * FROM sqlite_stat1; + SELECT * FROM sqlite_stat1 ORDER BY 1, 2; } -} {t1 t1i1 {1 1 1}} +} {t1 t1i1 {1 1 1} t2 {} 1} # Modify statistics in order to make the optimizer then that: #