Add support for hypothetical index on partitioned tables.

This commit is contained in:
Julien Rouhaud 2020-06-13 09:42:37 +02:00
parent 098c8069f1
commit 205482a733
7 changed files with 204 additions and 5 deletions

View file

@ -39,6 +39,14 @@ ifneq ($(MAJORVERSION),$(filter $(MAJORVERSION), 9.2 9.3 9.4))
REGRESS += hypo_brin
endif
ifeq ($(MAJORVERSION),10)
REGRESS += hypo_index_part_10
endif
ifneq ($(MAJORVERSION),$(filter $(MAJORVERSION), 9.2 9.3 9.4 9.5 9.6 10))
REGRESS += hypo_index_part
endif
DEBUILD_ROOT = /tmp/$(EXTENSION)
deb: release-zip

View file

@ -0,0 +1,65 @@
-- Hypothetical on partitioned tabled
CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer)
PARTITION BY LIST (id1);
CREATE TABLE hypo_part_1
PARTITION OF hypo_part FOR VALUES IN (1)
PARTITION BY LIST (id2);
CREATE TABLE hypo_part_1_1
PARTITION OF hypo_part_1 FOR VALUES IN (1);
INSERT INTO hypo_part SELECT 1, 1, generate_series(1, 10000);
ANALYZE hypo_part;
SET enable_seqscan = 0;
-- hypothetical index on root partitioned table should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part (id3)');
nb
----
1
(1 row)
SELECT 1, COUNT(*) FROM do_explain('SELECT * FROM hypo_part WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part.*';
?column? | count
----------+-------
1 | 1
(1 row)
SELECT hypopg_reset();
hypopg_reset
--------------
(1 row)
-- hypothetical index on non-root partitioned table should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part_1 (id3)');
nb
----
1
(1 row)
SELECT 2, COUNT(*) FROM do_explain('SELECT * FROM hypo_part_1 WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part.*';
?column? | count
----------+-------
2 | 1
(1 row)
SELECT hypopg_reset();
hypopg_reset
--------------
(1 row)
-- hypothetical index on partition should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part_1_1 (id3)');
nb
----
1
(1 row)
SELECT 3, COUNT(*) FROM do_explain('SELECT * FROM hypo_part_1_1 WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part.*';
?column? | count
----------+-------
3 | 1
(1 row)

View file

@ -0,0 +1,32 @@
-- Hypothetical on partitioned tabled
CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer)
PARTITION BY LIST (id1);
CREATE TABLE hypo_part_1
PARTITION OF hypo_part FOR VALUES IN (1)
PARTITION BY LIST (id2);
CREATE TABLE hypo_part_1_1
PARTITION OF hypo_part_1 FOR VALUES IN (1);
INSERT INTO hypo_part SELECT 1, 1, generate_series(1, 10000);
ANALYZE hypo_part;
-- hypothetical index on root partitioned table should not work
SELECT hypopg_create_index('CREATE INDEX ON hypo_part (id1)');
ERROR: hypopg: cannot create hypothetical index on partitioned table "hypo_part"
-- hypothetical index on non-root partitioned table should not work
SELECT hypopg_create_index('CREATE INDEX ON hypo_part_1 (id1)');
ERROR: hypopg: cannot create hypothetical index on partitioned table "hypo_part_1"
-- hypothetical index on partition should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part_1_1 (id3)');
nb
----
1
(1 row)
-- Should use hypothetical index
SET enable_seqscan = 0;
SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo_part WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part_1_1.*';
count
-------
1
(1 row)

View file

@ -17,6 +17,12 @@
#include "postgres.h"
#include "fmgr.h"
#if PG_VERSION_NUM >= 110000
#include "catalog/partition.h"
#include "nodes/pg_list.h"
#include "utils/lsyscache.h"
#endif
#include "include/hypopg.h"
#include "include/hypopg_import.h"
#include "include/hypopg_index.h"
@ -75,6 +81,7 @@ static void hypo_get_relation_info_hook(PlannerInfo *root,
RelOptInfo *rel);
static get_relation_info_hook_type prev_get_relation_info_hook = NULL;
static bool hypo_index_match_table(hypoIndex *entry, Oid relid);
static bool hypo_query_walker(Node *node);
void
@ -256,6 +263,35 @@ hypo_utility_hook(
}
static bool
hypo_index_match_table(hypoIndex *entry, Oid relid)
{
/* Hypothetical index on the exact same relation, use it. */
if (entry->relid == relid)
return true;
#if PG_VERSION_NUM >= 110000
/*
* If the table is a partition, see if the hypothetical index belongs to
* one of the partition parent.
*/
if (get_rel_relispartition(relid))
{
List *parents = get_partition_ancestors(relid);
ListCell *lc;
foreach(lc, parents)
{
Oid oid = lfirst_oid(lc);
if (oid == entry->relid)
return true;
}
}
#endif
return false;
}
/* Detect if the current utility command is compatible with hypothetical indexes
* i.e. an EXPLAIN, no ANALYZE
*/
@ -292,6 +328,7 @@ hypo_query_walker(Node *parsetree)
return false;
}
/* Reset the isExplain flag after each query */
static void
hypo_executorEnd_hook(QueryDesc *queryDesc)
@ -333,7 +370,7 @@ hypo_get_relation_info_hook(PlannerInfo *root,
{
hypoIndex *entry = (hypoIndex *) lfirst(lc);
if (entry->relid == relationObjectId)
if (hypo_index_match_table(entry, RelationGetRelid(relation)))
{
/*
* hypothetical index found, add it to the relation's

View file

@ -366,18 +366,19 @@ hypo_index_store_parsetree(IndexStmt *node, const char *queryString)
{
#if PG_VERSION_NUM >= 90300
case RELKIND_MATVIEW:
#endif
#if PG_VERSION_NUM >= 110000
case RELKIND_PARTITIONED_TABLE:
#endif
case RELKIND_RELATION:
/* this is supported */
break;
#if PG_VERSION_NUM >= 100000
#if PG_VERSION_NUM < 110000
#if PG_VERSION_NUM >= 100000 && PG_VERSION_NUM < 110000
case RELKIND_PARTITIONED_TABLE:
elog(ERROR, "hypopg: cannot create hypothetical index on"
" partitioned table \"%s\"", node->relation->relname);
#endif /* pg11- */
break;
#endif /* pg10- */
#endif
default:
elog(ERROR, "hypopg: \"%s\" is not a table"
#if PG_VERSION_NUM >= 90300

View file

@ -0,0 +1,30 @@
-- Hypothetical on partitioned tabled
CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer)
PARTITION BY LIST (id1);
CREATE TABLE hypo_part_1
PARTITION OF hypo_part FOR VALUES IN (1)
PARTITION BY LIST (id2);
CREATE TABLE hypo_part_1_1
PARTITION OF hypo_part_1 FOR VALUES IN (1);
INSERT INTO hypo_part SELECT 1, 1, generate_series(1, 10000);
ANALYZE hypo_part;
SET enable_seqscan = 0;
-- hypothetical index on root partitioned table should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part (id3)');
SELECT 1, COUNT(*) FROM do_explain('SELECT * FROM hypo_part WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part.*';
SELECT hypopg_reset();
-- hypothetical index on non-root partitioned table should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part_1 (id3)');
SELECT 2, COUNT(*) FROM do_explain('SELECT * FROM hypo_part_1 WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part.*';
SELECT hypopg_reset();
-- hypothetical index on partition should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part_1_1 (id3)');
SELECT 3, COUNT(*) FROM do_explain('SELECT * FROM hypo_part_1_1 WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part.*';

View file

@ -0,0 +1,26 @@
-- Hypothetical on partitioned tabled
CREATE TABLE hypo_part(id1 integer, id2 integer, id3 integer)
PARTITION BY LIST (id1);
CREATE TABLE hypo_part_1
PARTITION OF hypo_part FOR VALUES IN (1)
PARTITION BY LIST (id2);
CREATE TABLE hypo_part_1_1
PARTITION OF hypo_part_1 FOR VALUES IN (1);
INSERT INTO hypo_part SELECT 1, 1, generate_series(1, 10000);
ANALYZE hypo_part;
-- hypothetical index on root partitioned table should not work
SELECT hypopg_create_index('CREATE INDEX ON hypo_part (id1)');
-- hypothetical index on non-root partitioned table should not work
SELECT hypopg_create_index('CREATE INDEX ON hypo_part_1 (id1)');
-- hypothetical index on partition should work
SELECT COUNT(*) AS nb FROM hypopg_create_index('CREATE INDEX ON hypo_part_1_1 (id3)');
-- Should use hypothetical index
SET enable_seqscan = 0;
SELECT COUNT(*) FROM do_explain('SELECT * FROM hypo_part WHERE id3 = 1') e
WHERE e ~ 'Index.*<\d+>btree_hypo_part_1_1.*';