diff options
author | dan <dan@noemail.net> | 2016-08-03 16:14:33 +0000 |
---|---|---|
committer | dan <dan@noemail.net> | 2016-08-03 16:14:33 +0000 |
commit | d66e5794d1507ca44e9874401a59c081fec3132c (patch) | |
tree | 6a412a0133e93395edbe1db97010c248c22ba79a /src | |
parent | 78f9bb6c717275422a25dadd67df1bb3a2e3f971 (diff) | |
download | sqlite-d66e5794d1507ca44e9874401a59c081fec3132c.tar.gz sqlite-d66e5794d1507ca44e9874401a59c081fec3132c.zip |
Fix stat4-based cost estimates for vector range constraints.
FossilOrigin-Name: 18af74abc8ceae47ab9fbee3e3e5bb37db8fcba5
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 18 | ||||
-rw-r--r-- | src/sqliteInt.h | 5 | ||||
-rw-r--r-- | src/vdbemem.c | 53 | ||||
-rw-r--r-- | src/where.c | 32 |
4 files changed, 64 insertions, 44 deletions
diff --git a/src/expr.c b/src/expr.c index c469b463e..70f732693 100644 --- a/src/expr.c +++ b/src/expr.c @@ -340,7 +340,7 @@ int sqlite3ExprVectorSize(Expr *pExpr){ ** pointer to the i'th returned column value. Otherwise, return a copy ** of the first argument. */ -static Expr *exprVectorField(Expr *pVector, int i){ +Expr *sqlite3ExprVectorField(Expr *pVector, int i){ assert( i<sqlite3ExprVectorSize(pVector) ); if( sqlite3ExprIsVector(pVector) ){ if( pVector->op==TK_SELECT ){ @@ -2025,7 +2025,7 @@ int sqlite3FindInIndex( ** comparison is the same as the affinity of each column. If ** it not, it is not possible to use any index. */ for(i=0; i<nExpr && affinity_ok; i++){ - Expr *pLhs = exprVectorField(pX->pLeft, i); + Expr *pLhs = sqlite3ExprVectorField(pX->pLeft, i); int iCol = pEList->a[i].pExpr->iColumn; char idxaff = pTab->aCol[iCol].affinity; char cmpaff = sqlite3CompareAffinity(pLhs, idxaff); @@ -2051,7 +2051,7 @@ int sqlite3FindInIndex( } for(i=0; i<nExpr; i++){ - Expr *pLhs = exprVectorField(pX->pLeft, i); + Expr *pLhs = sqlite3ExprVectorField(pX->pLeft, i); Expr *pRhs = pEList->a[i].pExpr; CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; @@ -2156,7 +2156,7 @@ static char *exprINAffinity(Parse *pParse, Expr *pExpr){ if( zRet ){ int i; for(i=0; i<nVal; i++){ - Expr *pA = exprVectorField(pLeft, i); + Expr *pA = sqlite3ExprVectorField(pLeft, i); char a = sqlite3ExprAffinity(pA); if( pSelect ){ zRet[i] = sqlite3CompareAffinity(pSelect->pEList->a[i].pExpr, a); @@ -2308,7 +2308,7 @@ int sqlite3CodeSubselect( assert( pEList->nExpr>0 ); assert( sqlite3KeyInfoIsWriteable(pKeyInfo) ); for(i=0; i<nVal; i++){ - Expr *p = (nVal>1) ? exprVectorField(pLeft, i) : pLeft; + Expr *p = (nVal>1) ? sqlite3ExprVectorField(pLeft, i) : pLeft; pKeyInfo->aColl[i] = sqlite3BinaryCompareCollSeq( pParse, p, pEList->a[i].pExpr ); @@ -2540,7 +2540,7 @@ static void sqlite3ExprCodeIN( } }else{ for(i=0; i<nVector; i++){ - Expr *pLhs = exprVectorField(pLeft, i); + Expr *pLhs = sqlite3ExprVectorField(pLeft, i); sqlite3ExprCode(pParse, pLhs, r1+aiMap[i]); } } @@ -2599,7 +2599,7 @@ static void sqlite3ExprCodeIN( ** completely empty, or NULL otherwise. */ if( destIfNull==destIfFalse ){ for(i=0; i<nVector; i++){ - Expr *p = exprVectorField(pExpr->pLeft, i); + Expr *p = sqlite3ExprVectorField(pExpr->pLeft, i); if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull); } @@ -2638,7 +2638,7 @@ static void sqlite3ExprCodeIN( Expr *p; CollSeq *pColl; int r2 = sqlite3GetTempReg(pParse); - p = exprVectorField(pLeft, i); + p = sqlite3ExprVectorField(pLeft, i); pColl = sqlite3ExprCollSeq(pParse, p); sqlite3VdbeAddOp3(v, OP_Column, iIdx, i, r2); @@ -2656,7 +2656,7 @@ static void sqlite3ExprCodeIN( ** result is 1. */ sqlite3VdbeJumpHere(v, addr); for(i=0; i<nVector; i++){ - Expr *p = exprVectorField(pExpr->pLeft, i); + Expr *p = sqlite3ExprVectorField(pExpr->pLeft, i); if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, r1+aiMap[i], destIfNull); } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 56da61a2a..a9061b283 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4006,10 +4006,12 @@ int sqlite3ExprCheckIN(Parse*, Expr*); #ifdef SQLITE_ENABLE_STAT3_OR_STAT4 void sqlite3AnalyzeFunctions(void); -int sqlite3Stat4ProbeSetValue(Parse*,Index*,UnpackedRecord**,Expr*,u8,int,int*); +int sqlite3Stat4ProbeSetValue( + Parse*,Index*,UnpackedRecord**,Expr*,int,int,int*); int sqlite3Stat4ValueFromExpr(Parse*, Expr*, u8, sqlite3_value**); void sqlite3Stat4ProbeFree(UnpackedRecord*); int sqlite3Stat4Column(sqlite3*, const void*, int, int, sqlite3_value**); +char sqlite3IndexColumnAffinity(sqlite3*, Index*, int); #endif /* @@ -4269,5 +4271,6 @@ int sqlite3DbstatRegister(sqlite3*); int sqlite3ExprVectorSize(Expr *pExpr); int sqlite3ExprIsVector(Expr *pExpr); +Expr *sqlite3ExprVectorField(Expr*, int); #endif /* SQLITEINT_H */ diff --git a/src/vdbemem.c b/src/vdbemem.c index 04cb9c5c6..070952763 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -1520,9 +1520,9 @@ static int stat4ValueFromExpr( ** structures intended to be compared against sample index keys stored ** in the sqlite_stat4 table. ** -** A single call to this function attempts to populates field iVal (leftmost -** is 0 etc.) of the unpacked record with a value extracted from expression -** pExpr. Extraction of values is possible if: +** A single call to this function populates zero or more fields of the +** record starting with field iVal (fields are numbered from left to +** right starting with 0). A single field is populated if: ** ** * (pExpr==0). In this case the value is assumed to be an SQL NULL, ** @@ -1531,10 +1531,14 @@ static int stat4ValueFromExpr( ** * The sqlite3ValueFromExpr() function is able to extract a value ** from the expression (i.e. the expression is a literal value). ** -** If a value can be extracted, the affinity passed as the 5th argument -** is applied to it before it is copied into the UnpackedRecord. Output -** parameter *pbOk is set to true if a value is extracted, or false -** otherwise. +** Or, if pExpr is a TK_VECTOR, one field is populated for each of the +** vector components that match either of the two latter criteria listed +** above. +** +** Before any value is appended to the record, the affinity of the +** corresponding column within index pIdx is applied to it. Before +** this function returns, output parameter *pnExtract is set to the +** number of values appended to the record. ** ** When this function is called, *ppRec must either point to an object ** allocated by an earlier call to this function, or must be NULL. If it @@ -1550,22 +1554,33 @@ int sqlite3Stat4ProbeSetValue( Index *pIdx, /* Index being probed */ UnpackedRecord **ppRec, /* IN/OUT: Probe record */ Expr *pExpr, /* The expression to extract a value from */ - u8 affinity, /* Affinity to use */ + int nElem, /* Maximum number of values to append */ int iVal, /* Array element to populate */ - int *pbOk /* OUT: True if value was extracted */ + int *pnExtract /* OUT: Values appended to the record */ ){ - int rc; - sqlite3_value *pVal = 0; - struct ValueNewStat4Ctx alloc; + int rc = SQLITE_OK; + int nExtract = 0; - alloc.pParse = pParse; - alloc.pIdx = pIdx; - alloc.ppRec = ppRec; - alloc.iVal = iVal; + if( pExpr==0 || pExpr->op!=TK_SELECT ){ + int i; + struct ValueNewStat4Ctx alloc; + + alloc.pParse = pParse; + alloc.pIdx = pIdx; + alloc.ppRec = ppRec; + + for(i=0; i<nElem; i++){ + sqlite3_value *pVal = 0; + Expr *pElem = (pExpr ? sqlite3ExprVectorField(pExpr, i) : 0); + u8 aff = sqlite3IndexColumnAffinity(pParse->db, pIdx, iVal+i); + alloc.iVal = iVal+i; + rc = stat4ValueFromExpr(pParse, pElem, aff, &alloc, &pVal); + if( !pVal ) break; + nExtract++; + } + } - rc = stat4ValueFromExpr(pParse, pExpr, affinity, &alloc, &pVal); - assert( pVal==0 || pVal->db==pParse->db ); - *pbOk = (pVal!=0); + *pnExtract = nExtract; return rc; } diff --git a/src/where.c b/src/where.c index 3e8dea70a..a37ab1bbf 100644 --- a/src/where.c +++ b/src/where.c @@ -1207,7 +1207,7 @@ static LogEst whereRangeAdjust(WhereTerm *pTerm, LogEst nNew){ /* ** Return the affinity for a single column of an index. */ -static char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ +char sqlite3IndexColumnAffinity(sqlite3 *db, Index *pIdx, int iCol){ assert( iCol>=0 && iCol<pIdx->nColumn ); if( !pIdx->zColAff ){ if( sqlite3IndexAffinityStr(db, pIdx)==0 ) return SQLITE_AFF_BLOB; @@ -1384,7 +1384,8 @@ static int whereRangeScanEst( if( nEq==pBuilder->nRecValid ){ UnpackedRecord *pRec = pBuilder->pRec; tRowcnt a[2]; - u8 aff; + int nBtm = pLoop->u.btree.nBtm; + int nTop = pLoop->u.btree.nTop; /* Variable iLower will be set to the estimate of the number of rows in ** the index that are less than the lower bound of the range query. The @@ -1414,8 +1415,6 @@ static int whereRangeScanEst( testcase( pRec->nField!=pBuilder->nRecValid ); pRec->nField = pBuilder->nRecValid; } - aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq); - assert( nEq!=p->nKeyCol || aff==SQLITE_AFF_INTEGER ); /* Determine iLower and iUpper using ($P) only. */ if( nEq==0 ){ iLower = 0; @@ -1434,17 +1433,20 @@ static int whereRangeScanEst( if( p->aSortOrder[nEq] ){ /* The roles of pLower and pUpper are swapped for a DESC index */ SWAP(WhereTerm*, pLower, pUpper); + SWAP(int, nBtm, nTop); } /* If possible, improve on the iLower estimate using ($P:$L). */ if( pLower ){ - int bOk; /* True if value is extracted from pExpr */ + int n; /* Values extracted from pExpr */ Expr *pExpr = pLower->pExpr->pRight; - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nBtm, nEq, &n); + if( rc==SQLITE_OK && n ){ tRowcnt iNew; + u16 mask = WO_GT|WO_LE; + if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); iLwrIdx = whereKeyStats(pParse, p, pRec, 0, a); - iNew = a[0] + ((pLower->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); + iNew = a[0] + ((pLower->eOperator & mask) ? a[1] : 0); if( iNew>iLower ) iLower = iNew; nOut--; pLower = 0; @@ -1453,13 +1455,15 @@ static int whereRangeScanEst( /* If possible, improve on the iUpper estimate using ($P:$U). */ if( pUpper ){ - int bOk; /* True if value is extracted from pExpr */ + int n; /* Values extracted from pExpr */ Expr *pExpr = pUpper->pExpr->pRight; - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq, &bOk); - if( rc==SQLITE_OK && bOk ){ + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, nTop, nEq, &n); + if( rc==SQLITE_OK && n ){ tRowcnt iNew; + u16 mask = WO_GT|WO_LE; + if( sqlite3ExprVectorSize(pExpr)>n ) mask = (WO_LE|WO_LT); iUprIdx = whereKeyStats(pParse, p, pRec, 1, a); - iNew = a[0] + ((pUpper->eOperator & (WO_GT|WO_LE)) ? a[1] : 0); + iNew = a[0] + ((pUpper->eOperator & mask) ? a[1] : 0); if( iNew<iUpper ) iUpper = iNew; nOut--; pUpper = 0; @@ -1549,7 +1553,6 @@ static int whereEqualScanEst( Index *p = pBuilder->pNew->u.btree.pIndex; int nEq = pBuilder->pNew->u.btree.nEq; UnpackedRecord *pRec = pBuilder->pRec; - u8 aff; /* Column affinity */ int rc; /* Subfunction return code */ tRowcnt a[2]; /* Statistics */ int bOk; @@ -1573,8 +1576,7 @@ static int whereEqualScanEst( return SQLITE_OK; } - aff = sqlite3IndexColumnAffinity(pParse->db, p, nEq-1); - rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, aff, nEq-1, &bOk); + rc = sqlite3Stat4ProbeSetValue(pParse, p, &pRec, pExpr, 1, nEq-1, &bOk); pBuilder->pRec = pRec; if( rc!=SQLITE_OK ) return rc; if( bOk==0 ) return SQLITE_NOTFOUND; |