1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-07-27 20:41:58 +03:00

Enhance the geopoly virtual table so that it does a better job of optimizing

geopoly_within() queries.

FossilOrigin-Name: 1f717385340f295064a7649cfc36ad048573cbacb6faa20f5c6067328c40c745
This commit is contained in:
drh
2018-08-25 23:03:27 +00:00
parent 27d62540e5
commit e6474b77b8
4 changed files with 116 additions and 32 deletions

View File

@ -1109,7 +1109,9 @@ static int geopolyConnect(
** 1 rowid lookup
** 2 search for objects overlapping the same bounding box
** that contains polygon argv[0]
** 3 full table scan
** 3 search for objects overlapping the same bounding box
** that contains polygon argv[0]
** 4 full table scan
*/
static int geopolyFilter(
sqlite3_vtab_cursor *pVtabCursor, /* The cursor to initialize */
@ -1159,7 +1161,7 @@ static int geopolyFilter(
** with the configured constraints.
*/
rc = nodeAcquire(pRtree, 1, 0, &pRoot);
if( rc==SQLITE_OK && idxNum==2 ){
if( rc==SQLITE_OK && idxNum<=3 ){
RtreeCoord bbox[4];
RtreeConstraint *p;
assert( argc==1 );
@ -1174,21 +1176,41 @@ static int geopolyFilter(
}else{
memset(pCsr->aConstraint, 0, sizeof(RtreeConstraint)*4);
memset(pCsr->anQueue, 0, sizeof(u32)*(pRtree->iDepth + 1));
p->op = 'B';
p->iCoord = 0;
p->u.rValue = bbox[1].f;
p++;
p->op = 'D';
p->iCoord = 1;
p->u.rValue = bbox[0].f;
p++;
p->op = 'B';
p->iCoord = 2;
p->u.rValue = bbox[3].f;
p++;
p->op = 'D';
p->iCoord = 3;
p->u.rValue = bbox[2].f;
if( idxNum==2 ){
/* Overlap query */
p->op = 'B';
p->iCoord = 0;
p->u.rValue = bbox[1].f;
p++;
p->op = 'D';
p->iCoord = 1;
p->u.rValue = bbox[0].f;
p++;
p->op = 'B';
p->iCoord = 2;
p->u.rValue = bbox[3].f;
p++;
p->op = 'D';
p->iCoord = 3;
p->u.rValue = bbox[2].f;
}else{
/* Within query */
p->op = 'D';
p->iCoord = 0;
p->u.rValue = bbox[0].f;
p++;
p->op = 'B';
p->iCoord = 1;
p->u.rValue = bbox[1].f;
p++;
p->op = 'D';
p->iCoord = 2;
p->u.rValue = bbox[2].f;
p++;
p->op = 'B';
p->iCoord = 3;
p->u.rValue = bbox[3].f;
}
}
}
if( rc==SQLITE_OK ){
@ -1218,15 +1240,17 @@ static int geopolyFilter(
**
** idxNum idxStr Strategy
** ------------------------------------------------
** 1 Unused Direct lookup by rowid.
** 2 Unused R-tree query
** 3 Unused full-table scan.
** 1 "rowid" Direct lookup by rowid.
** 2 "rtree" R-tree overlap query using geopoly_overlap()
** 3 "rtree" R-tree within query using geopoly_within()
** 4 "fullscan" full-table scan.
** ------------------------------------------------
*/
static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
int ii;
int iRowidTerm = -1;
int iFuncTerm = -1;
int idxNum = 0;
for(ii=0; ii<pIdxInfo->nConstraint; ii++){
struct sqlite3_index_constraint *p = &pIdxInfo->aConstraint[ii];
@ -1235,8 +1259,12 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
iRowidTerm = ii;
break;
}
if( p->iColumn==0 && p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION ){
if( p->iColumn==0 && p->op>=SQLITE_INDEX_CONSTRAINT_FUNCTION ){
/* p->op==SQLITE_INDEX_CONSTRAINT_FUNCTION for geopoly_overlap()
** p->op==(SQLITE_INDEX_CONTRAINT_FUNCTION+1) for geopoly_within().
** See geopolyFindFunction() */
iFuncTerm = ii;
idxNum = p->op - SQLITE_INDEX_CONSTRAINT_FUNCTION + 2;
}
}
@ -1251,7 +1279,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
return SQLITE_OK;
}
if( iFuncTerm>=0 ){
pIdxInfo->idxNum = 2;
pIdxInfo->idxNum = idxNum;
pIdxInfo->idxStr = "rtree";
pIdxInfo->aConstraintUsage[iFuncTerm].argvIndex = 1;
pIdxInfo->aConstraintUsage[iFuncTerm].omit = 0;
@ -1259,7 +1287,7 @@ static int geopolyBestIndex(sqlite3_vtab *tab, sqlite3_index_info *pIdxInfo){
pIdxInfo->estimatedRows = 10;
return SQLITE_OK;
}
pIdxInfo->idxNum = 3;
pIdxInfo->idxNum = 4;
pIdxInfo->idxStr = "fullscan";
pIdxInfo->estimatedCost = 3000000.0;
pIdxInfo->estimatedRows = 100000;
@ -1461,7 +1489,7 @@ static int geopolyFindFunction(
if( nArg==2 && sqlite3_stricmp(zName, "geopoly_within")==0 ){
*pxFunc = geopolyWithinFunc;
*ppArg = 0;
return SQLITE_INDEX_CONSTRAINT_FUNCTION;
return SQLITE_INDEX_CONSTRAINT_FUNCTION+1;
}
return 0;
}