Factor all KeyInfo object allocations into a single function:

sqlite3KeyInfoAlloc().  Always allocate enough space so that 
sqlite3VdbeRecordCompare() can avoid checking boundaries and hence
run faster.

FossilOrigin-Name: 7301bedd94c8610568349953b18ff3575203e1b2
This commit is contained in:
drh 2013-08-05 19:11:29 +00:00
parent af5b2af77d
commit 323df7907e
8 changed files with 67 additions and 78 deletions

View File

@ -1,5 +1,5 @@
C Improve\sperformance\sof\ssqlite3VdbeRecordCompare()\sby\susing\san\sapproximation\nthat\smight\sgive\sfalse\snegatives\sand\sonly\srunning\sthe\smore\sexpensive\sexact\s\nsubexpression\sif\sthe\sapproximation\sfails.
D 2013-08-05T15:32:09.754
C Factor\sall\sKeyInfo\sobject\sallocations\sinto\sa\ssingle\sfunction:\nsqlite3KeyInfoAlloc().\s\sAlways\sallocate\senough\sspace\sso\sthat\s\nsqlite3VdbeRecordCompare()\scan\savoid\schecking\sboundaries\sand\shence\nrun\sfaster.
D 2013-08-05T19:11:29.094
F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
F Makefile.in 5e41da95d92656a5004b03d3576e8b226858a28e
F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@ -166,13 +166,13 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
F src/btree.c 3f7bbfd72efb1cbf6a49515c376a031767ec930a
F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca
F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2
F src/build.c fc76e1cd014840781e175f57f6de38917986943b
F src/build.c cee4724668ebc09bb482c1be30f96e0ae2474f9b
F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc
F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
F src/ctime.c 4262c227bc91cecc61ae37ed3a40f08069cfa267
F src/date.c 067a81c9942c497aafd2c260e13add8a7d0c7dd4
F src/delete.c 2317c814866d9aa71fea16b3faf4fdd4d6a49b94
F src/expr.c 2068a7c17e45f8bee6e44205b059aa30acbc71c5
F src/expr.c 7e55edefb8bd0b35b382ce9226c58472cd63a443
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
F src/fkey.c 914a6bbd987d857c41ac9d244efa6641f36faadb
F src/func.c 5c50c1ea31fd864b0fe921fe1a8d4c55acd609ef
@ -216,12 +216,12 @@ F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e
F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
F src/resolve.c 17e670996729ac41aadf6a31f57b4e6f29b3d819
F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0
F src/select.c 20369c82dc38eb4a77b458c8f6e353ef550580c9
F src/select.c 97273e41f57993e817bf0e816f9b19c4c07fc15b
F src/shell.c 52f975eae87c8338c4dfbf4c2842d2a0971f01fd
F src/sqlite.h.in 442c109e0c3447c34b1794971ecdb673ce08a843
F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0
F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
F src/sqliteInt.h 7c6ad474ce49ed18393c027be65c9532b7c9168f
F src/sqliteInt.h abae976c5cfc00333bd612fc1d31d64056ea1e63
F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@ -277,11 +277,11 @@ F src/update.c 7f3fe64d8f3b44c44a1eac293f0f85f87c355b7a
F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f
F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9
F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8
F src/vdbe.c d6048a720c197db2f0e7d618e918bd2e2eff0322
F src/vdbe.c 4914ae1d00045a5310aea9e0f7c9a8edd3d9f856
F src/vdbe.h 4f554b5627f26710c4c36d919110a3fc611ca5c4
F src/vdbeInt.h e9b7c6b165a31a4715c5aa97223d20d265515231
F src/vdbeapi.c 4d13580bd058b39623e8fcfc233b7df4b8191e8b
F src/vdbeaux.c 1a149d406d812b767d70c932dfc472d586d04c45
F src/vdbeaux.c d5cdd5bd5c063cc912df20b0bcadf78b6b351cb2
F src/vdbeblob.c 5dc79627775bd9a9b494dd956e26297946417d69
F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab
F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
@ -1105,7 +1105,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381
F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae
F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac
P 4b8b426f10f8ae13bf553f7adf5ae09383fa0bd4
R 338de61a71c3cd74b79152f7e9194e12
P 28979dcd16f53e0ddca8eed74b668834e2856f03
R a1cc3bea296ae01021d8d2b465ba6a3e
U drh
Z 467c61e8c494116a000cdb09272cb823
Z fdca2fea30eff049f879427aa25c6c1a

View File

@ -1 +1 @@
28979dcd16f53e0ddca8eed74b668834e2856f03
7301bedd94c8610568349953b18ff3575203e1b2

View File

@ -3805,25 +3805,20 @@ void sqlite3Reindex(Parse *pParse, Token *pName1, Token *pName2){
KeyInfo *sqlite3IndexKeyinfo(Parse *pParse, Index *pIdx){
int i;
int nCol = pIdx->nColumn;
int nBytes = sizeof(KeyInfo) + (nCol-1)*sizeof(CollSeq*) + nCol;
sqlite3 *db = pParse->db;
KeyInfo *pKey = (KeyInfo *)sqlite3DbMallocZero(db, nBytes);
KeyInfo *pKey;
pKey = sqlite3KeyInfoAlloc(pParse->db, nCol);
if( pKey ){
pKey->db = pParse->db;
pKey->aSortOrder = (u8 *)&(pKey->aColl[nCol]);
assert( &pKey->aSortOrder[nCol]==&(((u8 *)pKey)[nBytes]) );
for(i=0; i<nCol; i++){
char *zColl = pIdx->azColl[i];
assert( zColl );
pKey->aColl[i] = sqlite3LocateCollSeq(pParse, zColl);
pKey->aSortOrder[i] = pIdx->aSortOrder[i];
}
pKey->nField = (u16)nCol;
}
if( pParse->nErr ){
sqlite3DbFree(db, pKey);
sqlite3DbFree(pParse->db, pKey);
pKey = 0;
}
return pKey;

View File

@ -1692,10 +1692,9 @@ int sqlite3CodeSubselect(
switch( pExpr->op ){
case TK_IN: {
char affinity; /* Affinity of the LHS of the IN */
KeyInfo keyInfo; /* Keyinfo for the generated table */
static u8 sortOrder = 0; /* Fake aSortOrder for keyInfo */
int addr; /* Address of OP_OpenEphemeral instruction */
Expr *pLeft = pExpr->pLeft; /* the LHS of the IN operator */
KeyInfo *pKeyInfo = 0; /* Key information */
if( rMayHaveNull ){
sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);
@ -1719,9 +1718,7 @@ int sqlite3CodeSubselect(
pExpr->iTable = pParse->nTab++;
addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);
if( rMayHaveNull==0 ) sqlite3VdbeChangeP5(v, BTREE_UNORDERED);
memset(&keyInfo, 0, sizeof(keyInfo));
keyInfo.nField = 1;
keyInfo.aSortOrder = &sortOrder;
pKeyInfo = isRowid ? 0 : sqlite3KeyInfoAlloc(pParse->db, 1);
if( ExprHasProperty(pExpr, EP_xIsSelect) ){
/* Case 1: expr IN (SELECT ...)
@ -1738,11 +1735,12 @@ int sqlite3CodeSubselect(
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
pExpr->x.pSelect->iLimit = 0;
if( sqlite3Select(pParse, pExpr->x.pSelect, &dest) ){
sqlite3DbFree(pParse->db, pKeyInfo);
return 0;
}
pEList = pExpr->x.pSelect->pEList;
if( ALWAYS(pEList!=0 && pEList->nExpr>0) ){
keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
if( pKeyInfo && ALWAYS(pEList!=0 && pEList->nExpr>0) ){
pKeyInfo->aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,
pEList->a[0].pExpr);
}
}else if( ALWAYS(pExpr->x.pList!=0) ){
@ -1761,8 +1759,9 @@ int sqlite3CodeSubselect(
if( !affinity ){
affinity = SQLITE_AFF_NONE;
}
keyInfo.aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
keyInfo.aSortOrder = &sortOrder;
if( pKeyInfo ){
pKeyInfo->aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);
}
/* Loop through each expression in <exprlist>. */
r1 = sqlite3GetTempReg(pParse);
@ -1801,8 +1800,8 @@ int sqlite3CodeSubselect(
sqlite3ReleaseTempReg(pParse, r1);
sqlite3ReleaseTempReg(pParse, r2);
}
if( !isRowid ){
sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);
if( pKeyInfo ){
sqlite3VdbeChangeP4(v, addr, (void *)pKeyInfo, P4_KEYINFO_HANDOFF);
}
break;
}

View File

@ -802,6 +802,25 @@ static void selectInnerLoop(
}
}
/*
** Allocate a KeyInfo object sufficient for an index of N columns.
**
** Actually, always allocate one extra column for the rowid at the end
** of the index. So the KeyInfo returned will have space sufficient for
** N+1 columns.
*/
KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N){
KeyInfo *p = sqlite3DbMallocZero(db,
sizeof(KeyInfo) + (N+1)*(sizeof(CollSeq*)+1));
if( p ){
p->aSortOrder = (u8*)&p->aColl[N+1];
p->nField = (u16)N;
p->enc = ENC(db);
p->db = db;
}
return p;
}
/*
** Given an expression list, generate a KeyInfo structure that records
** the collating sequence for each expression in that expression list.
@ -818,25 +837,19 @@ static void selectInnerLoop(
** P4_KEYINFO_HANDOFF is the usual way of dealing with this.
*/
static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){
sqlite3 *db = pParse->db;
int nExpr;
KeyInfo *pInfo;
struct ExprList_item *pItem;
sqlite3 *db = pParse->db;
int i;
nExpr = pList->nExpr;
pInfo = sqlite3DbMallocZero(db, sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) );
pInfo = sqlite3KeyInfoAlloc(db, nExpr);
if( pInfo ){
pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr];
pInfo->nField = (u16)nExpr;
pInfo->enc = ENC(db);
pInfo->db = db;
for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){
CollSeq *pColl;
pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr);
if( !pColl ){
pColl = db->pDfltColl;
}
if( !pColl ) pColl = db->pDfltColl;
pInfo->aColl[i] = pColl;
pInfo->aSortOrder[i] = pItem->sortOrder;
}
@ -1942,23 +1955,17 @@ static int multiSelect(
assert( p->pRightmost==p );
nCol = p->pEList->nExpr;
pKeyInfo = sqlite3DbMallocZero(db,
sizeof(*pKeyInfo)+nCol*(sizeof(CollSeq*) + 1));
pKeyInfo = sqlite3KeyInfoAlloc(db, nCol);
if( !pKeyInfo ){
rc = SQLITE_NOMEM;
goto multi_select_end;
}
pKeyInfo->enc = ENC(db);
pKeyInfo->nField = (u16)nCol;
for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){
*apColl = multiSelectCollSeq(pParse, p, i);
if( 0==*apColl ){
*apColl = db->pDfltColl;
}
}
pKeyInfo->aSortOrder = (u8*)apColl;
for(pLoop=p; pLoop; pLoop=pLoop->pPrior){
for(i=0; i<2; i++){
@ -2327,12 +2334,8 @@ static int multiSelectOrderBy(
assert( pItem->iOrderByCol>0 && pItem->iOrderByCol<=p->pEList->nExpr );
aPermute[i] = pItem->iOrderByCol - 1;
}
pKeyMerge =
sqlite3DbMallocRaw(db, sizeof(*pKeyMerge)+nOrderBy*(sizeof(CollSeq*)+1));
pKeyMerge = sqlite3KeyInfoAlloc(db, nOrderBy);
if( pKeyMerge ){
pKeyMerge->aSortOrder = (u8*)&pKeyMerge->aColl[nOrderBy];
pKeyMerge->nField = (u16)nOrderBy;
pKeyMerge->enc = ENC(db);
for(i=0; i<nOrderBy; i++){
CollSeq *pColl;
Expr *pTerm = pOrderBy->a[i].pExpr;
@ -2369,12 +2372,8 @@ static int multiSelectOrderBy(
regPrev = pParse->nMem+1;
pParse->nMem += nExpr+1;
sqlite3VdbeAddOp2(v, OP_Integer, 0, regPrev);
pKeyDup = sqlite3DbMallocZero(db,
sizeof(*pKeyDup) + nExpr*(sizeof(CollSeq*)+1) );
pKeyDup = sqlite3KeyInfoAlloc(db, nExpr);
if( pKeyDup ){
pKeyDup->aSortOrder = (u8*)&pKeyDup->aColl[nExpr];
pKeyDup->nField = (u16)nExpr;
pKeyDup->enc = ENC(db);
for(i=0; i<nExpr; i++){
pKeyDup->aColl[i] = multiSelectCollSeq(pParse, p, i);
pKeyDup->aSortOrder[i] = 0;

View File

@ -1464,12 +1464,16 @@ struct FKey {
** An instance of the following structure is passed as the first
** argument to sqlite3VdbeKeyCompare and is used to control the
** comparison of the two index keys.
**
** Note that aSortOrder[] and aColl[] have nField+1 slots. There
** are nField slots for the columns of an index then one extra slot
** for the rowid at the end.
*/
struct KeyInfo {
sqlite3 *db; /* The database connection */
u8 enc; /* Text encoding - one of the SQLITE_UTF* values */
u16 nField; /* Number of entries in aColl[] */
u8 *aSortOrder; /* Sort order for each column. May be NULL */
u16 nField; /* Maximum index for aColl[] and aSortOrder[] */
u8 *aSortOrder; /* Sort order for each column. */
CollSeq *aColl[1]; /* Collating sequence for each term of the key */
};
@ -3086,6 +3090,7 @@ void sqlite3MinimumFileFormat(Parse*, int, int);
void sqlite3SchemaClear(void *);
Schema *sqlite3SchemaGet(sqlite3 *, Btree *);
int sqlite3SchemaToIndex(sqlite3 *db, Schema *);
KeyInfo *sqlite3KeyInfoAlloc(sqlite3*,int);
KeyInfo *sqlite3IndexKeyinfo(Parse *, Index *);
int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *,
void (*)(sqlite3_context*,int,sqlite3_value **),

View File

@ -555,7 +555,7 @@ int sqlite3VdbeExec(
int iCompare = 0; /* Result of last OP_Compare operation */
unsigned nVmStep = 0; /* Number of virtual machine steps */
#ifndef SQLITE_OMIT_PROGRESS_CALLBACK
unsigned nProgressLimit; /* Invoke xProgress() when nVmStep reaches this */
unsigned nProgressLimit = 0;/* Invoke xProgress() when nVmStep reaches this */
#endif
Mem *aMem = p->aMem; /* Copy of p->aMem */
Mem *pIn1 = 0; /* 1st input operand */

View File

@ -729,20 +729,13 @@ void sqlite3VdbeChangeP4(Vdbe *p, int addr, const char *zP4, int n){
pOp->p4.p = 0;
pOp->p4type = P4_NOTUSED;
}else if( n==P4_KEYINFO ){
KeyInfo *pKeyInfo;
int nField, nByte;
KeyInfo *pOrig, *pNew;
nField = ((KeyInfo*)zP4)->nField;
nByte = sizeof(*pKeyInfo) + (nField-1)*sizeof(pKeyInfo->aColl[0]) + nField;
pKeyInfo = sqlite3DbMallocRaw(0, nByte);
pOp->p4.pKeyInfo = pKeyInfo;
if( pKeyInfo ){
u8 *aSortOrder;
memcpy((char*)pKeyInfo, zP4, nByte - nField);
aSortOrder = pKeyInfo->aSortOrder;
assert( aSortOrder!=0 );
pKeyInfo->aSortOrder = (unsigned char*)&pKeyInfo->aColl[nField];
memcpy(pKeyInfo->aSortOrder, aSortOrder, nField);
pOrig = (KeyInfo*)zP4;
pOp->p4.pKeyInfo = pNew = sqlite3KeyInfoAlloc(db, pOrig->nField);
if( pNew ){
memcpy(pNew->aColl, pOrig->aColl, pOrig->nField*sizeof(pNew->aColl[0]));
memcpy(pNew->aSortOrder, pOrig->aSortOrder, pOrig->nField);
pOp->p4type = P4_KEYINFO;
}else{
p->db->mallocFailed = 1;
@ -2993,7 +2986,6 @@ int sqlite3VdbeRecordCompare(
u32 idx1; /* Offset into aKey[] of next header element */
u32 szHdr1; /* Number of bytes in header */
int i = 0;
int nField;
int rc = 0;
const unsigned char *aKey1 = (const unsigned char *)pKey1;
KeyInfo *pKeyInfo;
@ -3016,7 +3008,7 @@ int sqlite3VdbeRecordCompare(
idx1 = getVarint32(aKey1, szHdr1);
d1 = szHdr1;
nField = pKeyInfo->nField;
assert( pKeyInfo->nField+1>=pPKey2->nField );
assert( pKeyInfo->aSortOrder!=0 );
while( idx1<szHdr1 && i<pPKey2->nField ){
u32 serial_type1;
@ -3042,13 +3034,12 @@ int sqlite3VdbeRecordCompare(
/* Do the comparison
*/
rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i],
i<nField ? pKeyInfo->aColl[i] : 0);
rc = sqlite3MemCompare(&mem1, &pPKey2->aMem[i], pKeyInfo->aColl[i]);
if( rc!=0 ){
assert( mem1.zMalloc==0 ); /* See comment below */
/* Invert the result if we are using DESC sort order. */
if( i<nField && pKeyInfo->aSortOrder[i] ){
if( pKeyInfo->aSortOrder[i] ){
rc = -rc;
}