mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-01 06:27:03 +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:
@ -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;
|
||||
}
|
||||
|
@ -396,6 +396,34 @@ SELECT geopoly_svg(poly,
|
||||
FROM querypoly;
|
||||
.print '</svg>'
|
||||
|
||||
.print '<h1>Bounding-Box Overlap Query</h1>'
|
||||
.print '<pre>'
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT geopoly_svg(_shape,
|
||||
printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
|
||||
)
|
||||
FROM geo1, querypoly
|
||||
WHERE geopoly_overlap(geopoly_bbox(_shape), geopoly_bbox(poly));
|
||||
.print '</pre>'
|
||||
.print '<svg width="1000" height="800" style="border:1px solid black">'
|
||||
SELECT geopoly_svg(_shape,
|
||||
printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
|
||||
),
|
||||
geopoly_svg(geopoly_bbox(_shape),
|
||||
'style="fill:none;stroke:black;stroke-width:1"'
|
||||
)
|
||||
FROM geo1, querypoly
|
||||
WHERE geopoly_overlap(geopoly_bbox(_shape), geopoly_bbox(poly));
|
||||
SELECT geopoly_svg(poly,
|
||||
printf('style="fill:%s;fill-opacity:0.5;"',clr)
|
||||
)
|
||||
FROM querypoly;
|
||||
SELECT geopoly_svg(geopoly_bbox(poly),
|
||||
'style="fill:none;stroke:black;stroke-width:3"'
|
||||
)
|
||||
FROM querypoly;
|
||||
.print '</svg>'
|
||||
|
||||
.print '<h1>Within Query</h1>'
|
||||
.print '<pre>'
|
||||
EXPLAIN QUERY PLAN
|
||||
@ -417,6 +445,34 @@ SELECT geopoly_svg(poly,
|
||||
FROM querypoly;
|
||||
.print '</svg>'
|
||||
|
||||
.print '<h1>Bounding-Box WITHIN Query</h1>'
|
||||
.print '<pre>'
|
||||
EXPLAIN QUERY PLAN
|
||||
SELECT geopoly_svg(_shape,
|
||||
printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
|
||||
)
|
||||
FROM geo1, querypoly
|
||||
WHERE geopoly_within(geopoly_bbox(_shape), geopoly_bbox(poly));
|
||||
.print '</pre>'
|
||||
.print '<svg width="1000" height="800" style="border:1px solid black">'
|
||||
SELECT geopoly_svg(_shape,
|
||||
printf('style="fill:none;stroke:%s;stroke-width:1"',geo1.clr)
|
||||
),
|
||||
geopoly_svg(geopoly_bbox(_shape),
|
||||
'style="fill:none;stroke:black;stroke-width:1"'
|
||||
)
|
||||
FROM geo1, querypoly
|
||||
WHERE geopoly_within(geopoly_bbox(_shape), geopoly_bbox(poly));
|
||||
SELECT geopoly_svg(poly,
|
||||
printf('style="fill:%s;fill-opacity:0.5;"',clr)
|
||||
)
|
||||
FROM querypoly;
|
||||
SELECT geopoly_svg(geopoly_bbox(poly),
|
||||
'style="fill:none;stroke:black;stroke-width:3"'
|
||||
)
|
||||
FROM querypoly;
|
||||
.print '</svg>'
|
||||
|
||||
.print '<h1>Not Overlap Query</h1>'
|
||||
.print '<pre>'
|
||||
EXPLAIN QUERY PLAN
|
||||
|
Reference in New Issue
Block a user