1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-11-14 00:22:38 +03:00

Improve performance in single-threaded mode by having the final merge pass keys directly to the VDBE, instead of going via a final PMA.

FossilOrigin-Name: 02610cd9b77caa2c181210056088beb3ad6ce30f
This commit is contained in:
dan
2014-04-14 18:41:21 +00:00
parent 92a20dde1f
commit f77ceba594
3 changed files with 98 additions and 70 deletions

View File

@@ -1,5 +1,5 @@
C Minor\sfixes\sso\sthat\sbuilds\swith\sSQLITE_MAX_WORKER_THREADS=0\swork. C Improve\sperformance\sin\ssingle-threaded\smode\sby\shaving\sthe\sfinal\smerge\spass\skeys\sdirectly\sto\sthe\sVDBE,\sinstead\sof\sgoing\svia\sa\sfinal\sPMA.
D 2014-04-14T08:45:32.394 D 2014-04-14T18:41:21.894
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in ad0921c4b2780d01868cf69b419a4f102308d125 F Makefile.in ad0921c4b2780d01868cf69b419a4f102308d125
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -286,7 +286,7 @@ F src/vdbeapi.c 0ed6053f947edd0b30f64ce5aeb811872a3450a4
F src/vdbeaux.c d8dc38965507a34b0e150c0d7fc82b02f8cf25ea F src/vdbeaux.c d8dc38965507a34b0e150c0d7fc82b02f8cf25ea
F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa F src/vdbeblob.c 15377abfb59251bccedd5a9c7d014a895f0c04aa
F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447 F src/vdbemem.c 6fc77594c60f6155404f3f8d71bf36d1fdeb4447
F src/vdbesort.c 364cb94cf1eaefa1f79d86b7b1e4778c58192e1c F src/vdbesort.c 15f59dc56c7c4509b4783ad20fb25479ac63d267
F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767 F src/vdbetrace.c 6f52bc0c51e144b7efdcfb2a8f771167a8816767
F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd F src/vtab.c 21b932841e51ebd7d075e2d0ad1415dce8d2d5fd
F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8 F src/wal.c 76e7fc6de229bea8b30bb2539110f03a494dc3a8
@@ -1163,7 +1163,7 @@ F tool/vdbe_profile.tcl 67746953071a9f8f2f668b73fe899074e2c6d8c1
F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
P e1bdc4b810907cc0e55e0c923c8ebc777068cfe0 P e400bbbf26cdfe88f6cb231e96cdcddb9a6bcc0f
R 15b762d2cb0315f25703d6fa43b514ac R b74f7a073d8c77e32a2dce332520aa10
U dan U dan
Z 8e0f4aca92a8e556e8d49ca399252be9 Z cd43207b847b4088208c6c3dd9c99bf8

View File

@@ -1 +1 @@
e400bbbf26cdfe88f6cb231e96cdcddb9a6bcc0f 02610cd9b77caa2c181210056088beb3ad6ce30f

View File

@@ -280,21 +280,17 @@ struct MergeEngine {
struct VdbeSorter { struct VdbeSorter {
int mnPmaSize; /* Minimum PMA size, in bytes */ int mnPmaSize; /* Minimum PMA size, in bytes */
int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */ int mxPmaSize; /* Maximum PMA size, in bytes. 0==no limit */
int bUsePMA; /* True if one or more PMAs created */
int bUseThreads; /* True if one or more PMAs created */
PmaReader *pReader; /* Read data from here after Rewind() */ PmaReader *pReader; /* Read data from here after Rewind() */
MergeEngine *pMerger; /* Or here, if bUseThreads==0 */
int mxKeysize; /* Largest serialized key seen so far */ int mxKeysize; /* Largest serialized key seen so far */
UnpackedRecord *pUnpacked; /* Used by VdbeSorterCompare() */ UnpackedRecord *pUnpacked; /* Used by VdbeSorterCompare() */
#if 0 SorterList list; /* List of in-memory records */
int nInMemory; /* Current size of pRecord list as PMA */ int iMemory; /* Offset of free space in list.aMemory */
SorterRecord *pRecord; /* Head of in-memory record list */ int nMemory; /* Size of list.aMemory allocation in bytes */
u8 *aMemory; /* Block of memory to alloc records from */ u8 bUsePMA; /* True if one or more PMAs created */
#endif u8 bUseThreads; /* True to use background threads */
SorterList list; u8 iPrev; /* Previous thread used to flush PMA */
int iMemory; /* Offset of first free byte in aMemory */ u8 nTask; /* Size of aTask[] array */
int nMemory; /* Size of aMemory allocation in bytes */
int iPrev; /* Previous thread used to flush PMA */
int nTask; /* Size of aTask[] array */
SortSubtask aTask[1]; /* One or more subtasks */ SortSubtask aTask[1]; /* One or more subtasks */
}; };
@@ -1005,6 +1001,8 @@ void sqlite3VdbeSorterReset(sqlite3 *db, VdbeSorter *pSorter){
sqlite3DbFree(db, pSorter->pReader); sqlite3DbFree(db, pSorter->pReader);
pSorter->pReader = 0; pSorter->pReader = 0;
} }
vdbeMergeEngineFree(pSorter->pMerger);
pSorter->pMerger = 0;
for(i=0; i<pSorter->nTask; i++){ for(i=0; i<pSorter->nTask; i++){
SortSubtask *pTask = &pSorter->aTask[i]; SortSubtask *pTask = &pSorter->aTask[i];
vdbeSortSubtaskCleanup(db, pTask); vdbeSortSubtaskCleanup(db, pTask);
@@ -1713,22 +1711,39 @@ static void vdbeIncrSetThreads(IncrMerger *pIncr, int bUseThread){
#define INCRINIT2_NORMAL 0 #define INCRINIT2_NORMAL 0
#define INCRINIT2_TASK 1 #define INCRINIT2_TASK 1
#define INCRINIT2_ROOT 2 #define INCRINIT2_ROOT 2
static int vdbeIncrInit2(PmaReader *pIter, int eMode);
static int vdbeIncrInitMerger(
SortSubtask *pTask,
MergeEngine *pMerger,
int eMode
){
int i;
int rc = SQLITE_OK;
for(i=0; rc==SQLITE_OK && i<pMerger->nTree; i++){
if( eMode==INCRINIT2_ROOT ){
rc = vdbePmaReaderNext(&pMerger->aIter[i]);
}else{
rc = vdbeIncrInit2(&pMerger->aIter[i], INCRINIT2_NORMAL);
}
}
for(i=pMerger->nTree-1; rc==SQLITE_OK && i>0; i--){
rc = vdbeSorterDoCompare(pTask, pMerger, i);
}
return rc;
}
static int vdbeIncrInit2(PmaReader *pIter, int eMode){ static int vdbeIncrInit2(PmaReader *pIter, int eMode){
int rc = SQLITE_OK; int rc = SQLITE_OK;
IncrMerger *pIncr = pIter->pIncr; IncrMerger *pIncr = pIter->pIncr;
if( pIncr ){ if( pIncr ){
SortSubtask *pTask = pIncr->pTask; SortSubtask *pTask = pIncr->pTask;
int i;
MergeEngine *pMerger = pIncr->pMerger;
for(i=0; rc==SQLITE_OK && i<pMerger->nTree; i++){ rc = vdbeIncrInitMerger(pTask, pIncr->pMerger, eMode);
IncrMerger *p;
if( eMode==INCRINIT2_ROOT ){
rc = vdbePmaReaderNext(&pMerger->aIter[i]);
}else{
rc = vdbeIncrInit2(&pMerger->aIter[i], INCRINIT2_NORMAL);
}
}
/* Set up the required files for pIncr */ /* Set up the required files for pIncr */
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
@@ -1754,10 +1769,6 @@ static int vdbeIncrInit2(PmaReader *pIter, int eMode){
} }
} }
for(i=pMerger->nTree-1; rc==SQLITE_OK && i>0; i--){
rc = vdbeSorterDoCompare(pIncr->pTask, pMerger, i);
}
if( rc==SQLITE_OK && pIncr->bUseThread ){ if( rc==SQLITE_OK && pIncr->bUseThread ){
/* Use the current thread */ /* Use the current thread */
assert( eMode==INCRINIT2_ROOT || eMode==INCRINIT2_TASK ); assert( eMode==INCRINIT2_ROOT || eMode==INCRINIT2_TASK );
@@ -1871,7 +1882,7 @@ static int vdbeAddToBuilder(
** Populate iterator *pIter so that it may be used to iterate through all ** Populate iterator *pIter so that it may be used to iterate through all
** keys stored in all PMAs created by this sorter. ** keys stored in all PMAs created by this sorter.
*/ */
static int vdbePmaReaderIncrInit(VdbeSorter *pSorter, PmaReader *pIter){ static int vdbePmaReaderIncrInit(VdbeSorter *pSorter){
SortSubtask *pTask0 = &pSorter->aTask[0]; SortSubtask *pTask0 = &pSorter->aTask[0];
MergeEngine *pMain = 0; MergeEngine *pMain = 0;
sqlite3 *db = pTask0->db; sqlite3 *db = pTask0->db;
@@ -1943,39 +1954,49 @@ static int vdbePmaReaderIncrInit(VdbeSorter *pSorter, PmaReader *pIter){
} }
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1]; #if SQLITE_MAX_WORKER_THREADS
if( pSorter->bUseThreads ){
rc = vdbeSortAllocUnpacked(pLast); PmaReader *pIter;
if( rc==SQLITE_OK ){ SortSubtask *pLast = &pSorter->aTask[pSorter->nTask-1];
pIter->pIncr = vdbeIncrNew(pLast, pMain); rc = vdbeSortAllocUnpacked(pLast);
if( pIter->pIncr==0 ){ if( rc==SQLITE_OK ){
rc = SQLITE_NOMEM; pIter = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
pSorter->pReader = pIter;
} }
#if SQLITE_MAX_WORKER_THREADS>0 if( rc==SQLITE_OK ){
else{ pIter->pIncr = vdbeIncrNew(pLast, pMain);
vdbeIncrSetThreads(pIter->pIncr, pSorter->bUseThreads); if( pIter->pIncr==0 ){
for(iTask=0; iTask<(pSorter->nTask-1); iTask++){ rc = SQLITE_NOMEM;
IncrMerger *pIncr;
if( (pIncr = pMain->aIter[iTask].pIncr) ){
vdbeIncrSetThreads(pIncr, pSorter->bUseThreads);
assert( pIncr->pTask!=pLast );
}
} }
if( pSorter->nTask>1 ){ else{
for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){ vdbeIncrSetThreads(pIter->pIncr, pSorter->bUseThreads);
PmaReader *p = &pMain->aIter[iTask]; for(iTask=0; iTask<(pSorter->nTask-1); iTask++){
assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] ); IncrMerger *pIncr;
if( p->pIncr ){ rc = vdbeIncrBgInit2(p); } if( (pIncr = pMain->aIter[iTask].pIncr) ){
vdbeIncrSetThreads(pIncr, pSorter->bUseThreads);
assert( pIncr->pTask!=pLast );
}
}
if( pSorter->nTask>1 ){
for(iTask=0; rc==SQLITE_OK && iTask<pSorter->nTask; iTask++){
PmaReader *p = &pMain->aIter[iTask];
assert( p->pIncr==0 || p->pIncr->pTask==&pSorter->aTask[iTask] );
if( p->pIncr ){ rc = vdbeIncrBgInit2(p); }
}
} }
} }
} }
if( rc==SQLITE_OK ){
int eMode = (pSorter->nTask>1 ? INCRINIT2_ROOT : INCRINIT2_NORMAL);
rc = vdbeIncrInit2(pIter, eMode);
}
}else
#endif #endif
{
pSorter->pMerger = pMain;
rc = vdbeIncrInitMerger(pTask0, pMain, INCRINIT2_NORMAL);
} }
} }
if( rc==SQLITE_OK ){
int eMode = (pSorter->nTask>1 ? INCRINIT2_ROOT : INCRINIT2_NORMAL);
rc = vdbeIncrInit2(pIter, eMode);
}
sqlite3_free(aMerge); sqlite3_free(aMerge);
return rc; return rc;
@@ -2020,11 +2041,7 @@ int sqlite3VdbeSorterRewind(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
** incrementally read and merge all remaining PMAs. */ ** incrementally read and merge all remaining PMAs. */
assert( pSorter->pReader==0 ); assert( pSorter->pReader==0 );
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
PmaReader *pReader; rc = vdbePmaReaderIncrInit(pSorter);
pReader = (PmaReader*)sqlite3DbMallocZero(db, sizeof(PmaReader));
pSorter->pReader = pReader;
rc = vdbePmaReaderIncrInit(pSorter, pReader);
assert( rc!=SQLITE_OK || pReader->pFile );
*pbEof = 0; *pbEof = 0;
} }
@@ -2039,9 +2056,17 @@ int sqlite3VdbeSorterNext(sqlite3 *db, const VdbeCursor *pCsr, int *pbEof){
VdbeSorter *pSorter = pCsr->pSorter; VdbeSorter *pSorter = pCsr->pSorter;
int rc; /* Return code */ int rc; /* Return code */
if( pSorter->pReader ){ assert( pSorter->bUsePMA || (pSorter->pReader==0 && pSorter->pMerger==0) );
rc = vdbePmaReaderNext(pSorter->pReader); if( pSorter->bUsePMA ){
*pbEof = (pSorter->pReader->pFile==0); assert( pSorter->pReader==0 || pSorter->pMerger==0 );
assert( pSorter->bUseThreads==0 || pSorter->pReader );
assert( pSorter->bUseThreads==1 || pSorter->pMerger );
if( pSorter->bUseThreads ){
rc = vdbePmaReaderNext(pSorter->pReader);
*pbEof = (pSorter->pReader->pFile==0);
}else{
rc = vdbeSorterNext(&pSorter->aTask[0], pSorter->pMerger, pbEof);
}
}else{ }else{
SorterRecord *pFree = pSorter->list.pList; SorterRecord *pFree = pSorter->list.pList;
pSorter->list.pList = pFree->u.pNext; pSorter->list.pList = pFree->u.pNext;
@@ -2062,9 +2087,12 @@ static void *vdbeSorterRowkey(
int *pnKey /* OUT: Size of current key in bytes */ int *pnKey /* OUT: Size of current key in bytes */
){ ){
void *pKey; void *pKey;
if( pSorter->pReader ){ if( pSorter->bUsePMA ){
*pnKey = pSorter->pReader->nKey; PmaReader *pReader = (pSorter->bUseThreads ?
pKey = pSorter->pReader->aKey; pSorter->pReader : &pSorter->pMerger->aIter[pSorter->pMerger->aTree[1]]
);
*pnKey = pReader->nKey;
pKey = pReader->aKey;
}else{ }else{
*pnKey = pSorter->list.pList->nVal; *pnKey = pSorter->list.pList->nVal;
pKey = SRVAL(pSorter->list.pList); pKey = SRVAL(pSorter->list.pList);