Commit ff963b39 authored by Teodor Sigaev's avatar Teodor Sigaev

Add polygon opclass for SP-GiST

Polygon opclass uses compress method feature of SP-GiST added earlier. For now
it's a single operator class which uses this feature. SP-GiST actually indexes
a bounding boxes of input polygons, so part of supported operations are lossy.
Opclass uses most methods of corresponding opclass over boxes of SP-GiST and
treats bounding boxes as point in 4D-space.

Bump catalog version.

Authors: Nikita Glukhov, Alexander Korotkov with minor editorization by me
Reviewed-By: all authors + Darafei Praliaskouski
Discussion: https://www.postgresql.org/message-id/flat/54907069.1030506@sigaev.ru
parent 4e2970f8
...@@ -130,6 +130,42 @@ ...@@ -130,6 +130,42 @@
<literal>|&amp;&gt;</literal> <literal>|&amp;&gt;</literal>
</entry> </entry>
</row> </row>
<row>
<entry><literal>poly_ops</literal></entry>
<entry><type>polygon</type></entry>
<entry>
<literal>&lt;&lt;</literal>
<literal>&amp;&lt;</literal>
<literal>&amp;&amp;</literal>
<literal>&amp;&gt;</literal>
<literal>&gt;&gt;</literal>
<literal>~=</literal>
<literal>@&gt;</literal>
<literal>&lt;@</literal>
<literal>&amp;&lt;|</literal>
<literal>&lt;&lt;|</literal>
<literal>|&gt;&gt;</literal>
<literal>|&amp;&gt;</literal>
</entry>
</row>
<row>
<entry><literal>poly_ops</literal></entry>
<entry><type>polygon</type></entry>
<entry>
<literal>&lt;&lt;</literal>
<literal>&amp;&lt;</literal>
<literal>&amp;&amp;</literal>
<literal>&amp;&gt;</literal>
<literal>&gt;&gt;</literal>
<literal>~=</literal>
<literal>@&gt;</literal>
<literal>&lt;@</literal>
<literal>&amp;&lt;|</literal>
<literal>&lt;&lt;|</literal>
<literal>|&gt;&gt;</literal>
<literal>|&amp;&gt;</literal>
</entry>
</row>
<row> <row>
<entry><literal>text_ops</literal></entry> <entry><literal>text_ops</literal></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
......
...@@ -41,7 +41,6 @@ enum path_delim ...@@ -41,7 +41,6 @@ enum path_delim
static int point_inside(Point *p, int npts, Point *plist); static int point_inside(Point *p, int npts, Point *plist);
static int lseg_crossing(double x, double y, double px, double py); static int lseg_crossing(double x, double y, double px, double py);
static BOX *box_construct(double x1, double x2, double y1, double y2); static BOX *box_construct(double x1, double x2, double y1, double y2);
static BOX *box_copy(BOX *box);
static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2); static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);
static bool box_ov(BOX *box1, BOX *box2); static bool box_ov(BOX *box1, BOX *box2);
static double box_ht(BOX *box); static double box_ht(BOX *box);
...@@ -482,7 +481,7 @@ box_fill(BOX *result, double x1, double x2, double y1, double y2) ...@@ -482,7 +481,7 @@ box_fill(BOX *result, double x1, double x2, double y1, double y2)
/* box_copy - copy a box /* box_copy - copy a box
*/ */
static BOX * BOX *
box_copy(BOX *box) box_copy(BOX *box)
{ {
BOX *result = (BOX *) palloc(sizeof(BOX)); BOX *result = (BOX *) palloc(sizeof(BOX));
......
...@@ -391,7 +391,7 @@ spg_box_quad_choose(PG_FUNCTION_ARGS) ...@@ -391,7 +391,7 @@ spg_box_quad_choose(PG_FUNCTION_ARGS)
spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0); spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1); spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
BOX *centroid = DatumGetBoxP(in->prefixDatum), BOX *centroid = DatumGetBoxP(in->prefixDatum),
*box = DatumGetBoxP(in->datum); *box = DatumGetBoxP(in->leafDatum);
out->resultType = spgMatchNode; out->resultType = spgMatchNode;
out->result.matchNode.restDatum = BoxPGetDatum(box); out->result.matchNode.restDatum = BoxPGetDatum(box);
...@@ -473,6 +473,51 @@ spg_box_quad_picksplit(PG_FUNCTION_ARGS) ...@@ -473,6 +473,51 @@ spg_box_quad_picksplit(PG_FUNCTION_ARGS)
PG_RETURN_VOID(); PG_RETURN_VOID();
} }
/*
* Check if result of consistent method based on bounding box is exact.
*/
static bool
is_bounding_box_test_exact(StrategyNumber strategy)
{
switch (strategy)
{
case RTLeftStrategyNumber:
case RTOverLeftStrategyNumber:
case RTOverRightStrategyNumber:
case RTRightStrategyNumber:
case RTOverBelowStrategyNumber:
case RTBelowStrategyNumber:
case RTAboveStrategyNumber:
case RTOverAboveStrategyNumber:
return true;
default:
return false;
}
}
/*
* Get bounding box for ScanKey.
*/
static BOX *
spg_box_quad_get_scankey_bbox(ScanKey sk, bool *recheck)
{
switch (sk->sk_subtype)
{
case BOXOID:
return DatumGetBoxP(sk->sk_argument);
case POLYGONOID:
if (recheck && !is_bounding_box_test_exact(sk->sk_strategy))
*recheck = true;
return &DatumGetPolygonP(sk->sk_argument)->boundbox;
default:
elog(ERROR, "unrecognized scankey subtype: %d", sk->sk_subtype);
return NULL;
}
}
/* /*
* SP-GiST inner consistent function * SP-GiST inner consistent function
*/ */
...@@ -515,7 +560,11 @@ spg_box_quad_inner_consistent(PG_FUNCTION_ARGS) ...@@ -515,7 +560,11 @@ spg_box_quad_inner_consistent(PG_FUNCTION_ARGS)
centroid = getRangeBox(DatumGetBoxP(in->prefixDatum)); centroid = getRangeBox(DatumGetBoxP(in->prefixDatum));
queries = (RangeBox **) palloc(in->nkeys * sizeof(RangeBox *)); queries = (RangeBox **) palloc(in->nkeys * sizeof(RangeBox *));
for (i = 0; i < in->nkeys; i++) for (i = 0; i < in->nkeys; i++)
queries[i] = getRangeBox(DatumGetBoxP(in->scankeys[i].sk_argument)); {
BOX *box = spg_box_quad_get_scankey_bbox(&in->scankeys[i], NULL);
queries[i] = getRangeBox(box);
}
/* Allocate enough memory for nodes */ /* Allocate enough memory for nodes */
out->nNodes = 0; out->nNodes = 0;
...@@ -638,7 +687,9 @@ spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS) ...@@ -638,7 +687,9 @@ spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS)
for (i = 0; i < in->nkeys; i++) for (i = 0; i < in->nkeys; i++)
{ {
StrategyNumber strategy = in->scankeys[i].sk_strategy; StrategyNumber strategy = in->scankeys[i].sk_strategy;
Datum query = in->scankeys[i].sk_argument; BOX *box = spg_box_quad_get_scankey_bbox(&in->scankeys[i],
&out->recheck);
Datum query = BoxPGetDatum(box);
switch (strategy) switch (strategy)
{ {
...@@ -713,3 +764,36 @@ spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS) ...@@ -713,3 +764,36 @@ spg_box_quad_leaf_consistent(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(flag); PG_RETURN_BOOL(flag);
} }
/*
* SP-GiST config function for 2-D types that are lossy represented by their
* bounding boxes
*/
Datum
spg_bbox_quad_config(PG_FUNCTION_ARGS)
{
spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
cfg->prefixType = BOXOID; /* A type represented by its bounding box */
cfg->labelType = VOIDOID; /* We don't need node labels. */
cfg->leafType = BOXOID;
cfg->canReturnData = false;
cfg->longValuesOK = false;
PG_RETURN_VOID();
}
/*
* SP-GiST compress function for polygons
*/
Datum
spg_poly_quad_compress(PG_FUNCTION_ARGS)
{
POLYGON *polygon = PG_GETARG_POLYGON_P(0);
BOX *box;
box = box_copy(&polygon->boundbox);
PG_RETURN_BOX_P(box);
}
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 201711301 #define CATALOG_VERSION_NO 201712251
#endif #endif
...@@ -857,6 +857,22 @@ DATA(insert ( 5000 603 603 10 s 2570 4000 0 )); ...@@ -857,6 +857,22 @@ DATA(insert ( 5000 603 603 10 s 2570 4000 0 ));
DATA(insert ( 5000 603 603 11 s 2573 4000 0 )); DATA(insert ( 5000 603 603 11 s 2573 4000 0 ));
DATA(insert ( 5000 603 603 12 s 2572 4000 0 )); DATA(insert ( 5000 603 603 12 s 2572 4000 0 ));
/*
* SP-GiST poly_ops (supports polygons)
*/
DATA(insert ( 5008 604 604 1 s 485 4000 0 ));
DATA(insert ( 5008 604 604 2 s 486 4000 0 ));
DATA(insert ( 5008 604 604 3 s 492 4000 0 ));
DATA(insert ( 5008 604 604 4 s 487 4000 0 ));
DATA(insert ( 5008 604 604 5 s 488 4000 0 ));
DATA(insert ( 5008 604 604 6 s 491 4000 0 ));
DATA(insert ( 5008 604 604 7 s 490 4000 0 ));
DATA(insert ( 5008 604 604 8 s 489 4000 0 ));
DATA(insert ( 5008 604 604 9 s 2575 4000 0 ));
DATA(insert ( 5008 604 604 10 s 2574 4000 0 ));
DATA(insert ( 5008 604 604 11 s 2577 4000 0 ));
DATA(insert ( 5008 604 604 12 s 2576 4000 0 ));
/* /*
* GiST inet_ops * GiST inet_ops
*/ */
......
...@@ -334,6 +334,12 @@ DATA(insert ( 5000 603 603 2 5013 )); ...@@ -334,6 +334,12 @@ DATA(insert ( 5000 603 603 2 5013 ));
DATA(insert ( 5000 603 603 3 5014 )); DATA(insert ( 5000 603 603 3 5014 ));
DATA(insert ( 5000 603 603 4 5015 )); DATA(insert ( 5000 603 603 4 5015 ));
DATA(insert ( 5000 603 603 5 5016 )); DATA(insert ( 5000 603 603 5 5016 ));
DATA(insert ( 5008 604 604 1 5010 ));
DATA(insert ( 5008 604 604 2 5013 ));
DATA(insert ( 5008 604 604 3 5014 ));
DATA(insert ( 5008 604 604 4 5015 ));
DATA(insert ( 5008 604 604 5 5016 ));
DATA(insert ( 5008 604 604 6 5011 ));
/* BRIN opclasses */ /* BRIN opclasses */
/* minmax bytea */ /* minmax bytea */
......
...@@ -205,6 +205,7 @@ DATA(insert ( 4000 box_ops PGNSP PGUID 5000 603 t 0 )); ...@@ -205,6 +205,7 @@ DATA(insert ( 4000 box_ops PGNSP PGUID 5000 603 t 0 ));
DATA(insert ( 4000 quad_point_ops PGNSP PGUID 4015 600 t 0 )); DATA(insert ( 4000 quad_point_ops PGNSP PGUID 4015 600 t 0 ));
DATA(insert ( 4000 kd_point_ops PGNSP PGUID 4016 600 f 0 )); DATA(insert ( 4000 kd_point_ops PGNSP PGUID 4016 600 f 0 ));
DATA(insert ( 4000 text_ops PGNSP PGUID 4017 25 t 0 )); DATA(insert ( 4000 text_ops PGNSP PGUID 4017 25 t 0 ));
DATA(insert ( 4000 poly_ops PGNSP PGUID 5008 604 t 603 ));
DATA(insert ( 403 jsonb_ops PGNSP PGUID 4033 3802 t 0 )); DATA(insert ( 403 jsonb_ops PGNSP PGUID 4033 3802 t 0 ));
DATA(insert ( 405 jsonb_ops PGNSP PGUID 4034 3802 t 0 )); DATA(insert ( 405 jsonb_ops PGNSP PGUID 4034 3802 t 0 ));
DATA(insert ( 2742 jsonb_ops PGNSP PGUID 4036 3802 t 25 )); DATA(insert ( 2742 jsonb_ops PGNSP PGUID 4036 3802 t 25 ));
......
...@@ -186,5 +186,6 @@ DATA(insert OID = 4103 ( 3580 range_inclusion_ops PGNSP PGUID )); ...@@ -186,5 +186,6 @@ DATA(insert OID = 4103 ( 3580 range_inclusion_ops PGNSP PGUID ));
DATA(insert OID = 4082 ( 3580 pg_lsn_minmax_ops PGNSP PGUID )); DATA(insert OID = 4082 ( 3580 pg_lsn_minmax_ops PGNSP PGUID ));
DATA(insert OID = 4104 ( 3580 box_inclusion_ops PGNSP PGUID )); DATA(insert OID = 4104 ( 3580 box_inclusion_ops PGNSP PGUID ));
DATA(insert OID = 5000 ( 4000 box_ops PGNSP PGUID )); DATA(insert OID = 5000 ( 4000 box_ops PGNSP PGUID ));
DATA(insert OID = 5008 ( 4000 poly_ops PGNSP PGUID ));
#endif /* PG_OPFAMILY_H */ #endif /* PG_OPFAMILY_H */
...@@ -5335,6 +5335,11 @@ DESCR("SP-GiST support for quad tree over box"); ...@@ -5335,6 +5335,11 @@ DESCR("SP-GiST support for quad tree over box");
DATA(insert OID = 5016 ( spg_box_quad_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_box_quad_leaf_consistent _null_ _null_ _null_ )); DATA(insert OID = 5016 ( spg_box_quad_leaf_consistent PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 16 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_box_quad_leaf_consistent _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over box"); DESCR("SP-GiST support for quad tree over box");
DATA(insert OID = 5010 ( spg_bbox_quad_config PGNSP PGUID 12 1 0 0 0 f f f f t f i s 2 0 2278 "2281 2281" _null_ _null_ _null_ _null_ _null_ spg_bbox_quad_config _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over 2-D types represented by their bounding boxes");
DATA(insert OID = 5011 ( spg_poly_quad_compress PGNSP PGUID 12 1 0 0 0 f f f f t f i s 1 0 603 "604" _null_ _null_ _null_ _null_ _null_ spg_poly_quad_compress _null_ _null_ _null_ ));
DESCR("SP-GiST support for quad tree over polygons");
/* replication slots */ /* replication slots */
DATA(insert OID = 3779 ( pg_create_physical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 2249 "19 16 16" "{19,16,16,19,3220}" "{i,i,i,o,o}" "{slot_name,immediately_reserve,temporary,slot_name,lsn}" _null_ _null_ pg_create_physical_replication_slot _null_ _null_ _null_ )); DATA(insert OID = 3779 ( pg_create_physical_replication_slot PGNSP PGUID 12 1 0 0 0 f f f f t f v u 3 0 2249 "19 16 16" "{19,16,16,19,3220}" "{i,i,i,o,o}" "{slot_name,immediately_reserve,temporary,slot_name,lsn}" _null_ _null_ pg_create_physical_replication_slot _null_ _null_ _null_ ));
DESCR("create a physical replication slot"); DESCR("create a physical replication slot");
......
...@@ -178,9 +178,10 @@ typedef struct ...@@ -178,9 +178,10 @@ typedef struct
* in geo_ops.c * in geo_ops.c
*/ */
/* private point routines */ /* private routines */
extern double point_dt(Point *pt1, Point *pt2); extern double point_dt(Point *pt1, Point *pt2);
extern double point_sl(Point *pt1, Point *pt2); extern double point_sl(Point *pt1, Point *pt2);
extern double pg_hypot(double x, double y); extern double pg_hypot(double x, double y);
extern BOX *box_copy(BOX *box);
#endif /* GEO_DECLS_H */ #endif /* GEO_DECLS_H */
...@@ -227,3 +227,241 @@ SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner, ...@@ -227,3 +227,241 @@ SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
0 | 0 | 0 | 1.4142135623731 | 3.2 0 | 0 | 0 | 1.4142135623731 | 3.2
(1 row) (1 row)
--
-- Test the SP-GiST index
--
CREATE TABLE quad_poly_tbl (id int, p polygon);
INSERT INTO quad_poly_tbl
SELECT (x - 1) * 100 + y, polygon(circle(point(x * 10, y * 10), 1 + (x + y) % 10))
FROM generate_series(1, 100) x,
generate_series(1, 100) y;
INSERT INTO quad_poly_tbl
SELECT i, polygon '((200, 300),(210, 310),(230, 290))'
FROM generate_series(10001, 11000) AS i;
INSERT INTO quad_poly_tbl
VALUES
(11001, NULL),
(11002, NULL),
(11003, NULL);
CREATE INDEX quad_poly_tbl_idx ON quad_poly_tbl USING spgist(p);
-- get reference results for ORDER BY distance from seq scan
SET enable_seqscan = ON;
SET enable_indexscan = OFF;
SET enable_bitmapscan = OFF;
CREATE TABLE quad_poly_tbl_ord_seq1 AS
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl;
CREATE TABLE quad_poly_tbl_ord_seq2 AS
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
-- check results results from index scan
SET enable_seqscan = OFF;
SET enable_indexscan = OFF;
SET enable_bitmapscan = ON;
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
---------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p << '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p << '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
3890
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
---------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p &< '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p &< '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
7900
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
---------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p && '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p && '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
977
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
---------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p &> '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p &> '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
7000
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
---------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p >> '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p >> '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
2990
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
----------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p <<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p <<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
1890
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
----------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p &<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p &<| '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
6900
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
----------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p |&> '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p |&> '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
9000
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
----------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p |>> '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p |>> '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
3990
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
QUERY PLAN
---------------------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p <@ '((300,300),(400,600),(600,500),(700,200))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p <@ '((300,300),(400,600),(600,500),(700,200))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
count
-------
831
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
QUERY PLAN
-----------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p @> '((340,550),(343,552),(341,553))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p @> '((340,550),(343,552),(341,553))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
count
-------
1
(1 row)
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
QUERY PLAN
-----------------------------------------------------------------------------
Aggregate
-> Bitmap Heap Scan on quad_poly_tbl
Recheck Cond: (p ~= '((200,300),(210,310),(230,290))'::polygon)
-> Bitmap Index Scan on quad_poly_tbl_idx
Index Cond: (p ~= '((200,300),(210,310),(230,290))'::polygon)
(5 rows)
SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
count
-------
1000
(1 row)
RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
...@@ -166,6 +166,9 @@ point_tbl|t ...@@ -166,6 +166,9 @@ point_tbl|t
polygon_tbl|t polygon_tbl|t
quad_box_tbl|t quad_box_tbl|t
quad_point_tbl|t quad_point_tbl|t
quad_poly_tbl|t
quad_poly_tbl_ord_seq1|f
quad_poly_tbl_ord_seq2|f
radix_text_tbl|t radix_text_tbl|t
ramp|f ramp|f
real_city|f real_city|f
......
...@@ -116,3 +116,96 @@ SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner, ...@@ -116,3 +116,96 @@ SELECT '(0,0)'::point <-> '((0,0),(1,2),(2,1))'::polygon as on_corner,
'(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside, '(2,2)'::point <-> '((0,0),(1,4),(3,1))'::polygon as inside,
'(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner, '(3,3)'::point <-> '((0,2),(2,0),(2,2))'::polygon as near_corner,
'(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment; '(4,4)'::point <-> '((0,0),(0,3),(4,0))'::polygon as near_segment;
--
-- Test the SP-GiST index
--
CREATE TABLE quad_poly_tbl (id int, p polygon);
INSERT INTO quad_poly_tbl
SELECT (x - 1) * 100 + y, polygon(circle(point(x * 10, y * 10), 1 + (x + y) % 10))
FROM generate_series(1, 100) x,
generate_series(1, 100) y;
INSERT INTO quad_poly_tbl
SELECT i, polygon '((200, 300),(210, 310),(230, 290))'
FROM generate_series(10001, 11000) AS i;
INSERT INTO quad_poly_tbl
VALUES
(11001, NULL),
(11002, NULL),
(11003, NULL);
CREATE INDEX quad_poly_tbl_idx ON quad_poly_tbl USING spgist(p);
-- get reference results for ORDER BY distance from seq scan
SET enable_seqscan = ON;
SET enable_indexscan = OFF;
SET enable_bitmapscan = OFF;
CREATE TABLE quad_poly_tbl_ord_seq1 AS
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl;
CREATE TABLE quad_poly_tbl_ord_seq2 AS
SELECT rank() OVER (ORDER BY p <-> point '123,456') n, p <-> point '123,456' dist, id
FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
-- check results results from index scan
SET enable_seqscan = OFF;
SET enable_indexscan = OFF;
SET enable_bitmapscan = ON;
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p << polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p &< polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p && polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p &> polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p >> polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p <<| polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p &<| polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p |&> polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p |>> polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
SELECT count(*) FROM quad_poly_tbl WHERE p <@ polygon '((300,300),(400,600),(600,500),(700,200))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
SELECT count(*) FROM quad_poly_tbl WHERE p @> polygon '((340,550),(343,552),(341,553))';
EXPLAIN (COSTS OFF)
SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
SELECT count(*) FROM quad_poly_tbl WHERE p ~= polygon '((200, 300),(210, 310),(230, 290))';
RESET enable_seqscan;
RESET enable_indexscan;
RESET enable_bitmapscan;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment