1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-09-11 08:30:57 +03:00

Fix another problem in stat4 sample selection.

FossilOrigin-Name: d59f580904e6e7e90fc0a692a3dd4eeff5942479
This commit is contained in:
dan
2013-09-03 14:43:12 +00:00
parent 67a5ec7b54
commit b13af4c5dd
4 changed files with 98 additions and 45 deletions

View File

@@ -383,24 +383,63 @@ static const FuncDef statInitFuncdef = {
0 /* pDestructor */
};
#ifdef SQLITE_ENABLE_STAT4
/*
** pNew and pOld are both candidate non-periodic samples selected for
** the same column (pNew->iCol==pOld->iCol). Ignoring this column and
** considering only any trailing columns and the sample hash value, this
** function returns true if sample pNew is to be preferred over pOld.
** In other words, if we assume that the cardinalities of the selected
** column for pNew and pOld are equal, is pNew to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
** the anEq[] array from pSample->anEq[pSample->iCol+1] onwards are valid.
*/
static int sampleIsBetterPost(
Stat4Accum *pAccum,
Stat4Sample *pNew,
Stat4Sample *pOld
){
int nCol = pAccum->nCol;
int i;
assert( pNew->iCol==pOld->iCol );
for(i=pNew->iCol+1; i<nCol; i++){
if( pNew->anEq[i]>pOld->anEq[i] ) return 1;
if( pNew->anEq[i]<pOld->anEq[i] ) return 0;
}
if( pNew->iHash>pOld->iHash ) return 1;
return 0;
}
#endif
#ifdef SQLITE_ENABLE_STAT3_OR_STAT4
/*
** Return true if pNew is to be preferred over pOld.
**
** This function assumes that for each argument sample, the contents of
** the anEq[] array from pSample->anEq[pSample->iCol] onwards are valid.
*/
static int sampleIsBetter(Stat4Sample *pNew, Stat4Sample *pOld){
static int sampleIsBetter(
Stat4Accum *pAccum,
Stat4Sample *pNew,
Stat4Sample *pOld
){
tRowcnt nEqNew = pNew->anEq[pNew->iCol];
tRowcnt nEqOld = pOld->anEq[pOld->iCol];
assert( pOld->isPSample==0 && pNew->isPSample==0 );
assert( IsStat4 || (pNew->iCol==0 && pOld->iCol==0) );
if( (nEqNew>nEqOld)
|| (nEqNew==nEqOld && pNew->iCol<pOld->iCol)
|| (nEqNew==nEqOld && pNew->iCol==pOld->iCol && pNew->iHash>pOld->iHash)
){
return 1;
if( (nEqNew>nEqOld) ) return 1;
#ifdef SQLITE_ENABLE_STAT4
if( nEqNew==nEqOld ){
if( pNew->iCol<pOld->iCol ) return 1;
return (pNew->iCol==pOld->iCol && sampleIsBetterPost(pAccum, pNew, pOld));
}
return 0;
#else
return (nEqNew==nEqOld && pNew->iHash>pOld->iHash);
#endif
}
/*
@@ -423,8 +462,6 @@ void sampleCopy(Stat4Accum *p, Stat4Sample *pTo, Stat4Sample *pFrom){
static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
Stat4Sample *pSample;
int i;
i64 iSeq;
int iPos;
assert( IsStat4 || nEqZero==0 );
@@ -441,8 +478,9 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
Stat4Sample *pOld = &p->a[i];
if( pOld->anEq[pNew->iCol]==0 ){
if( pOld->isPSample ) return;
assert( sampleIsBetter(pNew, pOld) );
if( pUpgrade==0 || sampleIsBetter(pOld, pUpgrade) ){
assert( pOld->iCol>pNew->iCol );
assert( sampleIsBetter(p, pNew, pOld) );
if( pUpgrade==0 || sampleIsBetter(p, pOld, pUpgrade) ){
pUpgrade = pOld;
}
}
@@ -481,25 +519,6 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
sampleCopy(p, pSample, pNew);
p->nSample++;
#if 0
iSeq = pNew->anLt[p->nCol-1];
for(iPos=p->nSample; iPos>0; iPos--){
if( iSeq>p->a[iPos-1].anLt[p->nCol-1] ) break;
}
if( iPos!=p->nSample ){
Stat4Sample *pEnd = &p->a[p->nSample];
tRowcnt *anEq = pEnd->anEq;
tRowcnt *anLt = pEnd->anLt;
tRowcnt *anDLt = pEnd->anDLt;
memmove(&p->a[iPos], &p->a[iPos+1], (p->nSample-iPos)*sizeof(p->a[0]));
pSample->anEq = anEq;
pSample->anDLt = anDLt;
pSample->anLt = anLt;
}
#endif
/* Zero the first nEqZero entries in the anEq[] array. */
memset(pSample->anEq, 0, sizeof(tRowcnt)*nEqZero);
@@ -508,7 +527,7 @@ static void sampleInsert(Stat4Accum *p, Stat4Sample *pNew, int nEqZero){
int iMin = -1;
for(i=0; i<p->mxSample; i++){
if( p->a[i].isPSample ) continue;
if( iMin<0 || sampleIsBetter(&p->a[iMin], &p->a[i]) ){
if( iMin<0 || sampleIsBetter(p, &p->a[iMin], &p->a[i]) ){
iMin = i;
}
}
@@ -532,9 +551,8 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
** into IndexSample.a[] at this point. */
for(i=(p->nCol-2); i>=iChng; i--){
Stat4Sample *pBest = &p->aBest[i];
if( p->nSample<p->mxSample
|| sampleIsBetter(pBest, &p->a[p->iMin])
){
pBest->anEq[i] = p->current.anEq[i];
if( p->nSample<p->mxSample || sampleIsBetter(p, pBest, &p->a[p->iMin]) ){
sampleInsert(p, pBest, i);
}
}
@@ -561,7 +579,9 @@ static void samplePushPrevious(Stat4Accum *p, int iChng){
}else
/* Or if it is a non-periodic sample. Add it in this case too. */
if( p->nSample<p->mxSample || sampleIsBetter(&p->current, &p->a[p->iMin]) ){
if( p->nSample<p->mxSample
|| sampleIsBetter(p, &p->current, &p->a[p->iMin])
){
sampleInsert(p, &p->current, 0);
}
}
@@ -635,7 +655,7 @@ static void statPush(
/* Update the aBest[] array. */
for(i=0; i<(p->nCol-1); i++){
p->current.iCol = i;
if( i>=iChng || sampleIsBetter(&p->current, &p->aBest[i]) ){
if( i>=iChng || sampleIsBetterPost(p, &p->current, &p->aBest[i]) ){
sampleCopy(p, &p->aBest[i], &p->current);
}
}