]> granicus.if.org Git - postgresql/commitdiff
Support index-only scans in contrib/cube and contrib/seg GiST indexes.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 21 Nov 2017 01:25:18 +0000 (20:25 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 21 Nov 2017 01:25:18 +0000 (20:25 -0500)
To do this, we only have to remove the compress and decompress support
functions, which have never done anything more than detoasting.
In the wake of commit d3a4f89d8, this results in automatically enabling
index-only scans, since the core code will now know that the stored
representation is the same as the original data (up to detoasting).

The only exciting part of this is that ALTER OPERATOR FAMILY lacks
a way to drop a support function that was declared as being part of
an opclass rather than being loose in the family.  For the moment,
we'll hack our way to a solution with a manual update of the pg_depend
entry type, which is what distinguishes the two cases.  Perhaps
someday it'll be worth providing a cleaner way to do that, but for
now it seems like a very niche problem.

Note that the underlying C functions remain, to support use of the shared
libraries with older versions of the modules' SQL declarations.  Someday
we may be able to remove them, but not soon.

Andrey Borodin, reviewed by me

Discussion: https://postgr.es/m/D0F53A05-4F4A-4DEC-8339-3C069FA0EE11@yandex-team.ru

12 files changed:
contrib/cube/Makefile
contrib/cube/cube--1.3--1.4.sql [new file with mode: 0644]
contrib/cube/cube.control
contrib/cube/expected/cube.out
contrib/cube/expected/cube_2.out
contrib/cube/sql/cube.sql
contrib/seg/Makefile
contrib/seg/expected/seg.out
contrib/seg/expected/seg_1.out
contrib/seg/seg--1.2--1.3.sql [new file with mode: 0644]
contrib/seg/seg.control
contrib/seg/sql/seg.sql

index 244c1d9bbf370649f77e7e13d9ec4032bc635d61..accb7d28a39f73c69c338457605b636380e4090f 100644 (file)
@@ -4,7 +4,7 @@ MODULE_big = cube
 OBJS= cube.o cubeparse.o $(WIN32RES)
 
 EXTENSION = cube
-DATA = cube--1.2.sql cube--1.2--1.3.sql \
+DATA = cube--1.2.sql cube--1.2--1.3.sql cube--1.3--1.4.sql \
        cube--1.1--1.2.sql cube--1.0--1.1.sql \
        cube--unpackaged--1.0.sql
 PGFILEDESC = "cube - multidimensional cube data type"
diff --git a/contrib/cube/cube--1.3--1.4.sql b/contrib/cube/cube--1.3--1.4.sql
new file mode 100644 (file)
index 0000000..869820c
--- /dev/null
@@ -0,0 +1,45 @@
+/* contrib/cube/cube--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION cube UPDATE TO '1.4'" to load this file. \quit
+
+--
+-- Get rid of unnecessary compress and decompress support functions.
+--
+-- To be allowed to drop the opclass entry for a support function,
+-- we must change the entry's dependency type from 'internal' to 'auto',
+-- as though it were a loose member of the opfamily rather than being
+-- bound into a particular opclass.  There's no SQL command for that,
+-- so fake it with a manual update on pg_depend.
+--
+UPDATE pg_catalog.pg_depend
+SET deptype = 'a'
+WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+  AND objid =
+    (SELECT objid
+     FROM pg_catalog.pg_depend
+     WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+       AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass
+       AND (refobjid = 'g_cube_compress(pg_catalog.internal)'::pg_catalog.regprocedure))
+  AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass
+  AND deptype = 'i';
+
+ALTER OPERATOR FAMILY gist_cube_ops USING gist drop function 3 (cube);
+ALTER EXTENSION cube DROP function g_cube_compress(pg_catalog.internal);
+DROP FUNCTION g_cube_compress(pg_catalog.internal);
+
+UPDATE pg_catalog.pg_depend
+SET deptype = 'a'
+WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+  AND objid =
+    (SELECT objid
+     FROM pg_catalog.pg_depend
+     WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+       AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass
+       AND (refobjid = 'g_cube_decompress(pg_catalog.internal)'::pg_catalog.regprocedure))
+  AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass
+  AND deptype = 'i';
+
+ALTER OPERATOR FAMILY gist_cube_ops USING gist drop function 4 (cube);
+ALTER EXTENSION cube DROP function g_cube_decompress(pg_catalog.internal);
+DROP FUNCTION g_cube_decompress(pg_catalog.internal);
index af062d484368c85f126bcf168553981f6bd74269..f39a838e3f10d1418bdf841bdcf97fa5b4350021 100644 (file)
@@ -1,5 +1,5 @@
 # cube extension
 comment = 'data type for multidimensional cubes'
-default_version = '1.3'
+default_version = '1.4'
 module_pathname = '$libdir/cube'
 relocatable = true
index 328b3b5f5de42954d007ab104557cf1c3f658690..c430b4e1f0c5f1086371bb60cadb195e77d7be02 100644 (file)
@@ -1589,6 +1589,28 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c;
  (2424, 160),(2424, 81)
 (5 rows)
 
+-- Test index-only scans
+SET enable_bitmapscan = false;
+EXPLAIN (COSTS OFF)
+SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c;
+                       QUERY PLAN                       
+--------------------------------------------------------
+ Sort
+   Sort Key: c
+   ->  Index Only Scan using test_cube_ix on test_cube
+         Index Cond: (c <@ '(3000, 1000),(0, 0)'::cube)
+(4 rows)
+
+SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c;
+            c            
+-------------------------
+ (337, 455),(240, 359)
+ (759, 187),(662, 163)
+ (1444, 403),(1346, 344)
+ (2424, 160),(2424, 81)
+(4 rows)
+
+RESET enable_bitmapscan;
 -- kNN with index
 SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
             c            |       dist       
index 1aa5cf2f983cf112791df9b3976520aca0189d93..b979c4d6c88aa7bfcb9d50bb3d677addbfeaab80 100644 (file)
@@ -1589,6 +1589,28 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c;
  (2424, 160),(2424, 81)
 (5 rows)
 
+-- Test index-only scans
+SET enable_bitmapscan = false;
+EXPLAIN (COSTS OFF)
+SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c;
+                       QUERY PLAN                       
+--------------------------------------------------------
+ Sort
+   Sort Key: c
+   ->  Index Only Scan using test_cube_ix on test_cube
+         Index Cond: (c <@ '(3000, 1000),(0, 0)'::cube)
+(4 rows)
+
+SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c;
+            c            
+-------------------------
+ (337, 455),(240, 359)
+ (759, 187),(662, 163)
+ (1444, 403),(1346, 344)
+ (2424, 160),(2424, 81)
+(4 rows)
+
+RESET enable_bitmapscan;
 -- kNN with index
 SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
             c            |       dist       
index 58ea3ad81139ce11c23fe0a38cefd5f7c0724de0..eb24576895902c62bd5c6d3891df9d4f3f795527 100644 (file)
@@ -382,6 +382,13 @@ SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' ORDER BY c;
 -- Test sorting
 SELECT * FROM test_cube WHERE c && '(3000,1000),(0,0)' GROUP BY c ORDER BY c;
 
+-- Test index-only scans
+SET enable_bitmapscan = false;
+EXPLAIN (COSTS OFF)
+SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c;
+SELECT c FROM test_cube WHERE c <@ '(3000,1000),(0,0)' ORDER BY c;
+RESET enable_bitmapscan;
+
 -- kNN with index
 SELECT *, c <-> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <-> '(100, 100),(500, 500)'::cube LIMIT 5;
 SELECT *, c <=> '(100, 100),(500, 500)'::cube as dist FROM test_cube ORDER BY c <=> '(100, 100),(500, 500)'::cube LIMIT 5;
index 00a5472d3b94112f28dfca7ea3f7f5edb69bbbef..41270f84f626cb710f92c59b67c3dcc5bcc2b9b4 100644 (file)
@@ -4,7 +4,7 @@ MODULE_big = seg
 OBJS = seg.o segparse.o $(WIN32RES)
 
 EXTENSION = seg
-DATA = seg--1.1.sql seg--1.1--1.2.sql \
+DATA = seg--1.1.sql seg--1.1--1.2.sql seg--1.2--1.3.sql \
        seg--1.0--1.1.sql seg--unpackaged--1.0.sql
 PGFILEDESC = "seg - line segment data type"
 
index 18010c4d5cf506d264cb62418e7d60077fb2a764..a289dbe5f99c3c995404d3464939af0e4110b784 100644 (file)
@@ -930,12 +930,40 @@ SELECT '1'::seg <@ '-1 .. 1'::seg AS bool;
 CREATE TABLE test_seg (s seg);
 \copy test_seg from 'data/test_seg.data'
 CREATE INDEX test_seg_ix ON test_seg USING gist (s);
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on test_seg
+         Recheck Cond: (s @> '1.1e1 .. 11.3'::seg)
+         ->  Bitmap Index Scan on test_seg_ix
+               Index Cond: (s @> '1.1e1 .. 11.3'::seg)
+(5 rows)
+
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+ count 
+-------
+   143
+(1 row)
+
+SET enable_bitmapscan = false;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Aggregate
+   ->  Index Only Scan using test_seg_ix on test_seg
+         Index Cond: (s @> '1.1e1 .. 11.3'::seg)
+(3 rows)
+
 SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
  count 
 -------
    143
 (1 row)
 
+RESET enable_bitmapscan;
 -- Test sorting
 SELECT * FROM test_seg WHERE s @> '11..11.3' GROUP BY s;
         s        
index 566ce394ed0f4e2b1f970b85f16ab7c850fd6efb..48abb65bb0c38fe58b87b247a982370fe18316fb 100644 (file)
@@ -930,12 +930,40 @@ SELECT '1'::seg <@ '-1 .. 1'::seg AS bool;
 CREATE TABLE test_seg (s seg);
 \copy test_seg from 'data/test_seg.data'
 CREATE INDEX test_seg_ix ON test_seg USING gist (s);
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+                      QUERY PLAN                       
+-------------------------------------------------------
+ Aggregate
+   ->  Bitmap Heap Scan on test_seg
+         Recheck Cond: (s @> '1.1e1 .. 11.3'::seg)
+         ->  Bitmap Index Scan on test_seg_ix
+               Index Cond: (s @> '1.1e1 .. 11.3'::seg)
+(5 rows)
+
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+ count 
+-------
+   143
+(1 row)
+
+SET enable_bitmapscan = false;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Aggregate
+   ->  Index Only Scan using test_seg_ix on test_seg
+         Index Cond: (s @> '1.1e1 .. 11.3'::seg)
+(3 rows)
+
 SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
  count 
 -------
    143
 (1 row)
 
+RESET enable_bitmapscan;
 -- Test sorting
 SELECT * FROM test_seg WHERE s @> '11..11.3' GROUP BY s;
         s        
diff --git a/contrib/seg/seg--1.2--1.3.sql b/contrib/seg/seg--1.2--1.3.sql
new file mode 100644 (file)
index 0000000..cd71a30
--- /dev/null
@@ -0,0 +1,45 @@
+/* contrib/seg/seg--1.2--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION seg UPDATE TO '1.3'" to load this file. \quit
+
+--
+-- Get rid of unnecessary compress and decompress support functions.
+--
+-- To be allowed to drop the opclass entry for a support function,
+-- we must change the entry's dependency type from 'internal' to 'auto',
+-- as though it were a loose member of the opfamily rather than being
+-- bound into a particular opclass.  There's no SQL command for that,
+-- so fake it with a manual update on pg_depend.
+--
+UPDATE pg_catalog.pg_depend
+SET deptype = 'a'
+WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+  AND objid =
+    (SELECT objid
+     FROM pg_catalog.pg_depend
+     WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+       AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass
+       AND (refobjid = 'gseg_compress(pg_catalog.internal)'::pg_catalog.regprocedure))
+  AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass
+  AND deptype = 'i';
+
+ALTER OPERATOR FAMILY gist_seg_ops USING gist drop function 3 (seg);
+ALTER EXTENSION seg DROP function gseg_compress(pg_catalog.internal);
+DROP function gseg_compress(pg_catalog.internal);
+
+UPDATE pg_catalog.pg_depend
+SET deptype = 'a'
+WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+  AND objid =
+    (SELECT objid
+     FROM pg_catalog.pg_depend
+     WHERE classid = 'pg_catalog.pg_amproc'::pg_catalog.regclass
+       AND refclassid = 'pg_catalog.pg_proc'::pg_catalog.regclass
+       AND (refobjid = 'gseg_decompress(pg_catalog.internal)'::pg_catalog.regprocedure))
+  AND refclassid = 'pg_catalog.pg_opclass'::pg_catalog.regclass
+  AND deptype = 'i';
+
+ALTER OPERATOR FAMILY gist_seg_ops USING gist drop function 4 (seg);
+ALTER EXTENSION seg DROP function gseg_decompress(pg_catalog.internal);
+DROP function gseg_decompress(pg_catalog.internal);
index ba3d092c25376a5d49bacf2c6b425ae6877c72d1..d697cd6c2a8f9dea2980e28da8cd2653556a9b1c 100644 (file)
@@ -1,5 +1,5 @@
 # seg extension
 comment = 'data type for representing line segments or floating-point intervals'
-default_version = '1.2'
+default_version = '1.3'
 module_pathname = '$libdir/seg'
 relocatable = true
index aa9193147406d236bdb61839d877c4404da51f12..1d7bad7c37640c9332e60dbcbb0eff33d4b98663 100644 (file)
@@ -216,7 +216,16 @@ CREATE TABLE test_seg (s seg);
 \copy test_seg from 'data/test_seg.data'
 
 CREATE INDEX test_seg_ix ON test_seg USING gist (s);
+
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+
+SET enable_bitmapscan = false;
+EXPLAIN (COSTS OFF)
+SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
 SELECT count(*) FROM test_seg WHERE s @> '11..11.3';
+RESET enable_bitmapscan;
 
 -- Test sorting
 SELECT * FROM test_seg WHERE s @> '11..11.3' GROUP BY s;