From e34162b14f24aae2b478b917ceb6f516289ac39a Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 1 Apr 2015 18:20:25 +0000 Subject: [PATCH] When vacuuming an index that uses no collations other than BINARY, assume that the order of index entries will not be changed by the VACUUM. FossilOrigin-Name: e403460b96814ac8cb976d58b27939b3bd3c61f9 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/insert.c | 48 ++++++++++++++++++++++++++++++++++++++++-------- src/sqliteInt.h | 1 + src/vacuum.c | 4 ++++ 5 files changed, 54 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index be112fc01e..16584352e7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Reduce\sthe\sCPU\sused\sby\sCREATE\sINDEX\sstatements\sby\staking\sbetter\sadvantage\sof\sthe\sfact\sthat\skeys\sare\sinserted\sin\ssorted\sorder. -D 2015-04-01T16:18:00.779 +C When\svacuuming\san\sindex\sthat\suses\sno\scollations\sother\sthan\sBINARY,\sassume\sthat\sthe\sorder\sof\sindex\sentries\swill\snot\sbe\schanged\sby\sthe\sVACUUM. +D 2015-04-01T18:20:25.537 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 88a3e6261286db378fdffa1124cad11b3c05f5bb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -190,7 +190,7 @@ F src/global.c 4f77cadbc5427d00139ba43d0f3979804cbb700e F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 5b9243a33726008cc4132897d2be371db12a13be +F src/insert.c 1cc9dc4e939b5dd4a74ac4a3222b89e66b074210 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c 7274c97d24bb46631e504332ccd3bd1b37841770 @@ -235,7 +235,7 @@ F src/shell.c 3ae1e53878d2804fe77b8c8f1f6ca287a0e5d80e F src/sqlite.h.in 278602140d49575e8708e643161f4263e428a02a F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 17d487c3c91b0b8c584a32fbeb393f6f795eea7d -F src/sqliteInt.h bedf15914c09bfb5fe3ec4e3f211a4a6fc42cd33 +F src/sqliteInt.h df0ee3545220b8687d8640d433d1417b31e1675a F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c f266ad8a2892d659b74f0f50cb6a88b6e7c12179 F src/table.c e7a09215315a978057fb42c640f890160dbcc45e @@ -292,7 +292,7 @@ F src/trigger.c 25571661fdeae8c7f975ff40ffec205520a3f92f F src/update.c 3c4ecc282accf12d39edb8d524cf089645e55a13 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c 98a7627ca48ad3265b6940915a1d08355eb3fc7e -F src/vacuum.c 9460b9de7b2d4e34b0d374894aa6c8a0632be8ec +F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 F src/vdbe.c a9d916abb1e22355a81b0e72040917ba33c87ed7 F src/vdbe.h 7e538ecf47dccb307ea2d087c3ddc2dd8d70e79d F src/vdbeInt.h 9cbaa84f53ddd2d09a0cf61a94337a3a035d08a0 @@ -1247,7 +1247,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 0abfd78ceb09b7f7c27c688c8e3fe93268a13b32 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 601e7b6b8e6bfabda03b70f75094c9014e3a3c49 -R 151febe3c42a1563a662898adadb6b2d +P 592cdc5d7254be7032aa9c0b03405a74ca060b51 +R d93391642538d3e00eae6a1c718cf53f U dan -Z 37e9d6c37bda7e19a2c8ebf1573e150d +Z 6ea2b15ffbb091b1ac11e4173c1e9ec7 diff --git a/manifest.uuid b/manifest.uuid index 6bc7a444cf..180597c5c9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -592cdc5d7254be7032aa9c0b03405a74ca060b51 \ No newline at end of file +e403460b96814ac8cb976d58b27939b3bd3c61f9 \ No newline at end of file diff --git a/src/insert.c b/src/insert.c index a5c3f3e92d..f8ae4d7d3c 100644 --- a/src/insert.c +++ b/src/insert.c @@ -1765,6 +1765,7 @@ static int xferOptimization( int onError, /* How to handle constraint errors */ int iDbDest /* The database of pDest */ ){ + sqlite3 *db = pParse->db; ExprList *pEList; /* The result set of the SELECT */ Table *pSrc; /* The table in the FROM clause of SELECT */ Index *pSrcIdx, *pDestIdx; /* Source and destination indices */ @@ -1912,11 +1913,11 @@ static int xferOptimization( ** the extra complication to make this rule less restrictive is probably ** not worth the effort. Ticket [6284df89debdfa61db8073e062908af0c9b6118e] */ - if( (pParse->db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ + if( (db->flags & SQLITE_ForeignKeys)!=0 && pDest->pFKey!=0 ){ return 0; } #endif - if( (pParse->db->flags & SQLITE_CountRows)!=0 ){ + if( (db->flags & SQLITE_CountRows)!=0 ){ return 0; /* xfer opt does not play well with PRAGMA count_changes */ } @@ -1927,7 +1928,7 @@ static int xferOptimization( #ifdef SQLITE_TEST sqlite3_xferopt_count++; #endif - iDbSrc = sqlite3SchemaToIndex(pParse->db, pSrc->pSchema); + iDbSrc = sqlite3SchemaToIndex(db, pSrc->pSchema); v = sqlite3GetVdbe(pParse); sqlite3CodeVerifySchema(pParse, iDbSrc); iSrc = pParse->nTab++; @@ -1937,14 +1938,18 @@ static int xferOptimization( regRowid = sqlite3GetTempReg(pParse); sqlite3OpenTable(pParse, iDest, iDbDest, pDest, OP_OpenWrite); assert( HasRowid(pDest) || destHasUniqueIdx ); - if( (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ + if( (db->flags & SQLITE_Vacuum)==0 && ( + (pDest->iPKey<0 && pDest->pIndex!=0) /* (1) */ || destHasUniqueIdx /* (2) */ || (onError!=OE_Abort && onError!=OE_Rollback) /* (3) */ - ){ + )){ /* In some circumstances, we are able to run the xfer optimization - ** only if the destination table is initially empty. This code makes - ** that determination. Conditions under which the destination must - ** be empty: + ** only if the destination table is initially empty. Unless the + ** SQLITE_Vacuum flag is set, this block generates code to make + ** that determination. If SQLITE_Vacuum is set, then the destination + ** table is always empty. + ** + ** Conditions under which the destination must be empty: ** ** (1) There is no INTEGER PRIMARY KEY but there are indices. ** (If the destination is not initially empty, the rowid fields @@ -1987,6 +1992,7 @@ static int xferOptimization( sqlite3TableLock(pParse, iDbSrc, pSrc->tnum, 0, pSrc->zName); } for(pDestIdx=pDest->pIndex; pDestIdx; pDestIdx=pDestIdx->pNext){ + u8 useSeekResult = 0; for(pSrcIdx=pSrc->pIndex; ALWAYS(pSrcIdx); pSrcIdx=pSrcIdx->pNext){ if( xferCompatibleIndex(pDestIdx, pSrcIdx) ) break; } @@ -2000,7 +2006,33 @@ static int xferOptimization( VdbeComment((v, "%s", pDestIdx->zName)); addr1 = sqlite3VdbeAddOp2(v, OP_Rewind, iSrc, 0); VdbeCoverage(v); sqlite3VdbeAddOp2(v, OP_RowKey, iSrc, regData); + if( db->flags & SQLITE_Vacuum ){ + /* This INSERT command is part of a VACUUM operation, which guarantees + ** that the destination table is empty. If all indexed columns use + ** collation sequence BINARY, then it can also be assumed that the + ** index will be populated by inserting keys in strictly sorted + ** order. In this case, instead of seeking within the b-tree as part + ** of every OP_IdxInsert opcode, an OP_Last is added before the + ** OP_IdxInsert to seek to the point within the b-tree where each key + ** should be inserted. This is faster. + ** + ** If any of the indexed columns use a collation sequence other than + ** BINARY, this optimization is disabled. This is because the user + ** might change the definition of a collation sequence and then run + ** a VACUUM command. In that case keys may not be written in strictly + ** sorted order. */ + int i; + for(i=0; inColumn; i++){ + char *zColl = pSrcIdx->azColl[i]; + if( zColl && sqlite3_stricmp("BINARY", zColl) ) break; + } + if( i==pSrcIdx->nColumn ){ + useSeekResult = OPFLAG_USESEEKRESULT; + sqlite3VdbeAddOp3(v, OP_Last, iDest, 0, -1); + } + } sqlite3VdbeAddOp3(v, OP_IdxInsert, iDest, regData, 1); + sqlite3VdbeChangeP5(v, useSeekResult); sqlite3VdbeAddOp2(v, OP_Next, iSrc, addr1+1); VdbeCoverage(v); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp2(v, OP_Close, iSrc, 0); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 9df6d1bc4e..5e49bf58ff 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1226,6 +1226,7 @@ struct sqlite3 { #define SQLITE_DeferFKs 0x01000000 /* Defer all FK constraints */ #define SQLITE_QueryOnly 0x02000000 /* Disable database changes */ #define SQLITE_VdbeEQP 0x04000000 /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_Vacuum 0x08000000 /* Currently in a VACUUM */ /* diff --git a/src/vacuum.c b/src/vacuum.c index dca43e217e..adc802e60b 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -250,6 +250,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ ** an "INSERT INTO vacuum_db.xxx SELECT * FROM main.xxx;" to copy ** the contents to the temporary database. */ + assert( (db->flags & SQLITE_Vacuum)==0 ); + db->flags |= SQLITE_Vacuum; rc = execExecSql(db, pzErrMsg, "SELECT 'INSERT INTO vacuum_db.' || quote(name) " "|| ' SELECT * FROM main.' || quote(name) || ';'" @@ -257,6 +259,8 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ "WHERE type = 'table' AND name!='sqlite_sequence' " " AND coalesce(rootpage,1)>0" ); + assert( (db->flags & SQLITE_Vacuum)!=0 ); + db->flags &= ~SQLITE_Vacuum; if( rc!=SQLITE_OK ) goto end_of_vacuum; /* Copy over the sequence table -- 2.47.2