Skip to content

Commit

Permalink
Don't propagate FK lookup queries to osm chunks
Browse files Browse the repository at this point in the history
Skip the OSM chunk when doing hypertable expansion for FK lookup
queries. OSM chunks are considered archived data and we dont want
to incur the performance hit of querying OSM data on modifications
on the FK reference table.
  • Loading branch information
svenklemm committed Jul 31, 2024
1 parent e7850a8 commit 3572635
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 13 deletions.
12 changes: 11 additions & 1 deletion src/planner/expand_hypertable.c
Original file line number Diff line number Diff line change
Expand Up @@ -1046,11 +1046,21 @@ ts_plan_expand_hypertable_chunks(Hypertable *ht, PlannerInfo *root, RelOptInfo *
/* Can have zero chunks. */
Assert(num_chunks == 0 || chunks != NULL);

/*
* We need to mark the RowMark for the hypertable as parent
* to trigger inclusion of tableoid to allow for correctly
* identifying tuples from individual chunks.
*/
PlanRowMark *oldrc = get_plan_rowmark(root->rowMarks, rti);
if (oldrc)
{
oldrc->isParent = true;
}

for (unsigned int i = 0; i < num_chunks; i++)
{
if (!chunks[i]->fd.osm_chunk || include_osm)
inh_oids = lappend_oid(inh_oids, chunks[i]->table_id);

/*
* Add the information about chunks to the baserel info cache for
* classify_relation().
Expand Down
27 changes: 18 additions & 9 deletions src/planner/planner.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,24 @@ static void
rte_mark_for_expansion(RangeTblEntry *rte)
{
Assert(rte->rtekind == RTE_RELATION);
Assert(rte->ctename == NULL || rte->ctename == TS_FK_EXPAND);
if (rte->ctename != TS_FK_EXPAND)
rte->ctename = (char *) TS_CTE_EXPAND;
Assert(rte->ctename == NULL);
rte->ctename = (char *) TS_CTE_EXPAND;
rte->inh = false;
}

static void
rte_mark_for_fk_expansion(RangeTblEntry *rte)
{
Assert(rte->rtekind == RTE_RELATION);
Assert(rte->ctename == NULL);
rte->ctename = (char *) TS_FK_EXPAND;
/*
* If this is for an FK lookup query inherit should be false
* initially for hypertables.
*/
Assert(!rte->inh);
}

bool
ts_rte_is_marked_for_expansion(const RangeTblEntry *rte)
{
Expand Down Expand Up @@ -461,8 +473,7 @@ preprocess_query(Node *node, PreprocessQueryContext *context)
ts_hypertable_cache_get_entry(hcache, rte->relid, CACHE_FLAG_MISSING_OK);
if (ht)
{
rte->ctename = (char *) TS_FK_EXPAND;
rte->inh = true;
rte_mark_for_fk_expansion(rte);
if (TS_HYPERTABLE_HAS_COMPRESSION_ENABLED(ht))
query->rowMarks = NIL;
}
Expand Down Expand Up @@ -491,13 +502,11 @@ preprocess_query(Node *node, PreprocessQueryContext *context)
{
if (ts_hypertable_cache_get_entry(hcache, rte1->relid, CACHE_FLAG_MISSING_OK))
{
rte1->ctename = (char *) TS_FK_EXPAND;
rte1->inh = true;
rte_mark_for_fk_expansion(rte1);
}
if (ts_hypertable_cache_get_entry(hcache, rte2->relid, CACHE_FLAG_MISSING_OK))
{
rte2->ctename = (char *) TS_FK_EXPAND;
rte2->inh = true;
rte_mark_for_fk_expansion(rte2);
}
}
}
Expand Down
19 changes: 17 additions & 2 deletions tsl/test/expected/chunk_utils_internal.out
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,7 @@ ORDER BY table_name;
\c :TEST_DBNAME :ROLE_4
CREATE TABLE measure( id integer PRIMARY KEY, mname varchar(10));
INSERT INTO measure VALUES( 1, 'temp');
INSERT INTO measure VALUES( 2, 'osmtemp');
CREATE TABLE hyper_constr ( id integer, time bigint, temp float, mid integer
,PRIMARY KEY (id, time)
,FOREIGN KEY ( mid) REFERENCES measure(id)
Expand All @@ -880,7 +881,7 @@ SELECT create_hypertable('hyper_constr', 'time', chunk_time_interval => 10);
INSERT INTO hyper_constr VALUES( 10, 200, 22, 1);
\c postgres_fdw_db :ROLE_4
CREATE TABLE fdw_hyper_constr(id integer, time bigint, temp float, mid integer);
INSERT INTO fdw_hyper_constr VALUES( 10, 100, 33, 1);
INSERT INTO fdw_hyper_constr VALUES( 10, 100, 33, 2);
\c :TEST_DBNAME :ROLE_4
-- this is a stand-in for the OSM table
CREATE FOREIGN TABLE child_hyper_constr
Expand Down Expand Up @@ -914,7 +915,7 @@ ORDER BY table_name;
SELECT * FROM hyper_constr order by time;
id | time | temp | mid
----+------+------+-----
10 | 100 | 33 | 1
10 | 100 | 33 | 2
10 | 200 | 22 | 1
(2 rows)

Expand All @@ -926,6 +927,18 @@ where conrelid = 'child_hyper_constr'::regclass ORDER BY 1;
hyper_constr_temp_check
(1 row)

-- TEST foreign key trigger: deleting data from foreign table measure
-- does not error out due to data in osm chunk
\set ON_ERROR_STOP 0
BEGIN;
DELETE FROM measure where id = 1;
ERROR: update or delete on table "measure" violates foreign key constraint "hyper_constr_mid_fkey" on table "hyper_constr"
ROLLBACK;
--this touches osm chunk. should succeed silently without deleteing any data
BEGIN;
DELETE FROM measure where id = 2;
ROLLBACK;
\set ON_ERROR_STOP 1
--TEST retention policy is applied on OSM chunk by calling registered callback
CREATE OR REPLACE FUNCTION dummy_now_smallint() RETURNS BIGINT LANGUAGE SQL IMMUTABLE as 'SELECT 500::bigint' ;
SELECT set_integer_now_func('hyper_constr', 'dummy_now_smallint');
Expand Down Expand Up @@ -1090,6 +1103,7 @@ SELECT indexname, tablename FROM pg_indexes WHERE indexname = 'hyper_constr_mid_
(1 row)

DROP INDEX hyper_constr_mid_idx;
-- TEST for hypertable_osm_range_update function
-- test range of dimension slice for osm chunk for different datatypes
CREATE TABLE osm_int2(time int2 NOT NULL);
CREATE TABLE osm_int4(time int4 NOT NULL);
Expand Down Expand Up @@ -1227,6 +1241,7 @@ WHERE c.hypertable_id = :htid AND cc.chunk_id = c.id AND ds.id = cc.dimension_sl
25 | _hyper_15_25_chunk | 0 | t | 22 | 9223372036854775806 | 9223372036854775807
(1 row)

-- TEST for orderedappend that depends on hypertable_osm_range_update functionality
-- test further with ordered append
\c postgres_fdw_db :ROLE_4;
CREATE TABLE test_chunkapp_fdw (time timestamptz NOT NULL, a int);
Expand Down
18 changes: 17 additions & 1 deletion tsl/test/sql/chunk_utils_internal.sql
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ ORDER BY table_name;
\c :TEST_DBNAME :ROLE_4
CREATE TABLE measure( id integer PRIMARY KEY, mname varchar(10));
INSERT INTO measure VALUES( 1, 'temp');
INSERT INTO measure VALUES( 2, 'osmtemp');

CREATE TABLE hyper_constr ( id integer, time bigint, temp float, mid integer
,PRIMARY KEY (id, time)
Expand All @@ -485,7 +486,7 @@ INSERT INTO hyper_constr VALUES( 10, 200, 22, 1);

\c postgres_fdw_db :ROLE_4
CREATE TABLE fdw_hyper_constr(id integer, time bigint, temp float, mid integer);
INSERT INTO fdw_hyper_constr VALUES( 10, 100, 33, 1);
INSERT INTO fdw_hyper_constr VALUES( 10, 100, 33, 2);

\c :TEST_DBNAME :ROLE_4
-- this is a stand-in for the OSM table
Expand All @@ -510,6 +511,19 @@ SELECT * FROM hyper_constr order by time;
SELECT conname FROM pg_constraint
where conrelid = 'child_hyper_constr'::regclass ORDER BY 1;

-- TEST foreign key trigger: deleting data from foreign table measure
-- does not error out due to data in osm chunk
\set ON_ERROR_STOP 0
BEGIN;
DELETE FROM measure where id = 1;
ROLLBACK;

--this touches osm chunk. should succeed silently without deleteing any data
BEGIN;
DELETE FROM measure where id = 2;
ROLLBACK;
\set ON_ERROR_STOP 1

--TEST retention policy is applied on OSM chunk by calling registered callback
CREATE OR REPLACE FUNCTION dummy_now_smallint() RETURNS BIGINT LANGUAGE SQL IMMUTABLE as 'SELECT 500::bigint' ;

Expand Down Expand Up @@ -611,6 +625,7 @@ CREATE INDEX hyper_constr_mid_idx ON hyper_constr(mid, time) WITH (timescaledb.t
SELECT indexname, tablename FROM pg_indexes WHERE indexname = 'hyper_constr_mid_idx';
DROP INDEX hyper_constr_mid_idx;

-- TEST for hypertable_osm_range_update function
-- test range of dimension slice for osm chunk for different datatypes
CREATE TABLE osm_int2(time int2 NOT NULL);
CREATE TABLE osm_int4(time int4 NOT NULL);
Expand Down Expand Up @@ -669,6 +684,7 @@ SELECT cc.chunk_id, c.table_name, c.status, c.osm_chunk, cc.dimension_slice_id,
FROM _timescaledb_catalog.chunk c, _timescaledb_catalog.chunk_constraint cc, _timescaledb_catalog.dimension_slice ds
WHERE c.hypertable_id = :htid AND cc.chunk_id = c.id AND ds.id = cc.dimension_slice_id ORDER BY cc.chunk_id;

-- TEST for orderedappend that depends on hypertable_osm_range_update functionality
-- test further with ordered append
\c postgres_fdw_db :ROLE_4;
CREATE TABLE test_chunkapp_fdw (time timestamptz NOT NULL, a int);
Expand Down

0 comments on commit 3572635

Please sign in to comment.