Skip to content

Commit f41cf0c

Browse files
committed
Improve compressed DML expression pushdown
Try to constify query constraints when filtering batches to cover a wider range of expressions that are safe to evaluate when we do the batch filtering. This will allow the following expressions to be usable with compressed DML batch filtering: - IMMUTABLE and STABLE functions - SQLValueFunction (CURRENT_TIME,CURRENT_USER,LOCAL_TIME,...) - Prepared Statement parameters
1 parent ca125cf commit f41cf0c

File tree

4 files changed

+228
-80
lines changed

4 files changed

+228
-80
lines changed

.unreleased/pr_6895

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Implements: #6895 Improve compressed DML expression pushdown

tsl/src/compression/compression.c

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include <nodes/execnodes.h>
2525
#include <nodes/pg_list.h>
2626
#include <nodes/print.h>
27+
#include <optimizer/optimizer.h>
2728
#include <parser/parsetree.h>
2829
#include <parser/parse_coerce.h>
2930
#include <storage/lmgr.h>
@@ -2531,18 +2532,27 @@ find_matching_index(Relation comp_chunk_rel, List **index_filters, List **heap_f
25312532

25322533
/*
25332534
* This method will evaluate the predicates, extract
2534-
* left and right operands, check if one of the operands is
2535-
* a simple Var type. If its Var type extract its corresponding
2536-
* column name from hypertable_compression catalog table.
2537-
* If extracted column is a SEGMENT BY column then save column
2538-
* name, value specified in the predicate. This information will
2539-
* be used to build scan keys later.
2535+
* left and right operands, check if any of the operands
2536+
* can be used for batch filtering and if so, it will
2537+
* create a BatchFilter object and add it to the corresponding
2538+
* list.
2539+
* Any segmentby filter is put into index_filters list other
2540+
* filters are put into heap_filters list.
25402541
*/
25412542
static void
25422543
process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates, List **heap_filters,
25432544
List **index_filters, List **is_null)
25442545
{
25452546
ListCell *lc;
2547+
/*
2548+
* We dont want to forward boundParams from the execution state here
2549+
* as we dont want to constify join params in the predicates.
2550+
* Constifying JOIN params would not be safe as we don't redo
2551+
* this part in rescan.
2552+
*/
2553+
PlannerGlobal glob = { .boundParams = NULL };
2554+
PlannerInfo root = { .glob = &glob };
2555+
25462556
foreach (lc, predicates)
25472557
{
25482558
Node *node = copyObject(lfirst(lc));
@@ -2565,7 +2575,11 @@ process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates, L
25652575
continue;
25662576

25672577
if (!IsA(expr, Const))
2568-
continue;
2578+
{
2579+
expr = (Expr *) estimate_expression_value(&root, (Node *) expr);
2580+
if (!IsA(expr, Const))
2581+
continue;
2582+
}
25692583

25702584
arg_value = castNode(Const, expr);
25712585

tsl/test/expected/compression_update_delete.out

Lines changed: 166 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
-- This file and its contents are licensed under the Timescale License.
22
-- Please see the included NOTICE for copyright information and
33
-- LICENSE-TIMESCALE for a copy of the license.
4+
\set EXPLAIN 'EXPLAIN (costs off, timing off, summary off, analyze)'
45
CREATE OR REPLACE VIEW compressed_chunk_info_view AS
56
SELECT
67
h.schema_name AS hypertable_schema,
@@ -2944,106 +2945,215 @@ EXPLAIN (analyze, timing off, costs off, summary off) DELETE FROM test_meta_filt
29442945
Rows Removed by Filter: 10
29452946
(8 rows)
29462947

2947-
-- test commutator handling in compressed dml constraints
2948-
CREATE TABLE test_commutator(time timestamptz NOT NULL, device text);
2949-
SELECT table_name FROM create_hypertable('test_commutator', 'time');
2950-
table_name
2951-
-----------------
2952-
test_commutator
2953-
(1 row)
2954-
2955-
INSERT INTO test_commutator SELECT '2020-01-01', 'a';
2956-
INSERT INTO test_commutator SELECT '2020-01-01', 'b';
2957-
INSERT INTO test_commutator SELECT '2020-01-01', 'c';
2958-
ALTER TABLE test_commutator SET (timescaledb.compress, timescaledb.compress_segmentby='device');
2959-
NOTICE: default order by for hypertable "test_commutator" is set to ""time" DESC"
2960-
SELECT compress_chunk(show_chunks('test_commutator'));
2948+
-- test expression pushdown in compressed dml constraints
2949+
CREATE TABLE test_pushdown(time timestamptz NOT NULL, device text);
2950+
SELECT table_name FROM create_hypertable('test_pushdown', 'time');
2951+
table_name
2952+
---------------
2953+
test_pushdown
2954+
(1 row)
2955+
2956+
INSERT INTO test_pushdown SELECT '2020-01-01', 'a';
2957+
INSERT INTO test_pushdown SELECT '2020-01-01', 'b';
2958+
INSERT INTO test_pushdown SELECT '2020-01-01 05:00', 'c';
2959+
CREATE TABLE devices(device text);
2960+
INSERT INTO devices VALUES ('a'), ('b'), ('c');
2961+
ALTER TABLE test_pushdown SET (timescaledb.compress, timescaledb.compress_segmentby='device');
2962+
NOTICE: default order by for hypertable "test_pushdown" is set to ""time" DESC"
2963+
SELECT compress_chunk(show_chunks('test_pushdown'));
29612964
compress_chunk
29622965
------------------------------------------
29632966
_timescaledb_internal._hyper_39_79_chunk
29642967
(1 row)
29652968

2966-
BEGIN; EXPLAIN (costs off, timing off, summary off, analyze) DELETE FROM test_commutator WHERE 'a' = device; ROLLBACK;
2967-
QUERY PLAN
2968-
--------------------------------------------------------------------------------------
2969+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE 'a' = device; ROLLBACK;
2970+
QUERY PLAN
2971+
------------------------------------------------------------------------------------
29692972
Custom Scan (HypertableModify) (actual rows=0 loops=1)
29702973
Batches decompressed: 1
29712974
Tuples decompressed: 1
2972-
-> Delete on test_commutator (actual rows=0 loops=1)
2973-
Delete on _hyper_39_79_chunk test_commutator_1
2974-
-> Seq Scan on _hyper_39_79_chunk test_commutator_1 (actual rows=1 loops=1)
2975+
-> Delete on test_pushdown (actual rows=0 loops=1)
2976+
Delete on _hyper_39_79_chunk test_pushdown_1
2977+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=1 loops=1)
29752978
Filter: ('a'::text = device)
29762979
(7 rows)
29772980

2978-
BEGIN; EXPLAIN (costs off, timing off, summary off, analyze) DELETE FROM test_commutator WHERE device < 'c' ; ROLLBACK;
2979-
QUERY PLAN
2980-
--------------------------------------------------------------------------------------
2981+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE device < 'c' ; ROLLBACK;
2982+
QUERY PLAN
2983+
------------------------------------------------------------------------------------
29812984
Custom Scan (HypertableModify) (actual rows=0 loops=1)
29822985
Batches decompressed: 2
29832986
Tuples decompressed: 2
2984-
-> Delete on test_commutator (actual rows=0 loops=1)
2985-
Delete on _hyper_39_79_chunk test_commutator_1
2986-
-> Seq Scan on _hyper_39_79_chunk test_commutator_1 (actual rows=2 loops=1)
2987+
-> Delete on test_pushdown (actual rows=0 loops=1)
2988+
Delete on _hyper_39_79_chunk test_pushdown_1
2989+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=2 loops=1)
29872990
Filter: (device < 'c'::text)
29882991
(7 rows)
29892992

2990-
BEGIN; EXPLAIN (costs off, timing off, summary off, analyze) DELETE FROM test_commutator WHERE 'c' > device; ROLLBACK;
2991-
QUERY PLAN
2992-
--------------------------------------------------------------------------------------
2993+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE 'c' > device; ROLLBACK;
2994+
QUERY PLAN
2995+
------------------------------------------------------------------------------------
29932996
Custom Scan (HypertableModify) (actual rows=0 loops=1)
29942997
Batches decompressed: 2
29952998
Tuples decompressed: 2
2996-
-> Delete on test_commutator (actual rows=0 loops=1)
2997-
Delete on _hyper_39_79_chunk test_commutator_1
2998-
-> Seq Scan on _hyper_39_79_chunk test_commutator_1 (actual rows=2 loops=1)
2999+
-> Delete on test_pushdown (actual rows=0 loops=1)
3000+
Delete on _hyper_39_79_chunk test_pushdown_1
3001+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=2 loops=1)
29993002
Filter: ('c'::text > device)
30003003
(7 rows)
30013004

3002-
BEGIN; EXPLAIN (costs off, timing off, summary off, analyze) DELETE FROM test_commutator WHERE 'c' >= device; ROLLBACK;
3003-
QUERY PLAN
3004-
--------------------------------------------------------------------------------------
3005+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE 'c' >= device; ROLLBACK;
3006+
QUERY PLAN
3007+
------------------------------------------------------------------------------------
30053008
Custom Scan (HypertableModify) (actual rows=0 loops=1)
30063009
Batches decompressed: 3
30073010
Tuples decompressed: 3
3008-
-> Delete on test_commutator (actual rows=0 loops=1)
3009-
Delete on _hyper_39_79_chunk test_commutator_1
3010-
-> Seq Scan on _hyper_39_79_chunk test_commutator_1 (actual rows=3 loops=1)
3011+
-> Delete on test_pushdown (actual rows=0 loops=1)
3012+
Delete on _hyper_39_79_chunk test_pushdown_1
3013+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=3 loops=1)
30113014
Filter: ('c'::text >= device)
30123015
(7 rows)
30133016

3014-
BEGIN; EXPLAIN (costs off, timing off, summary off, analyze) DELETE FROM test_commutator WHERE device > 'b'; ROLLBACK;
3015-
QUERY PLAN
3016-
--------------------------------------------------------------------------------------
3017+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE device > 'b'; ROLLBACK;
3018+
QUERY PLAN
3019+
------------------------------------------------------------------------------------
30173020
Custom Scan (HypertableModify) (actual rows=0 loops=1)
30183021
Batches decompressed: 1
30193022
Tuples decompressed: 1
3020-
-> Delete on test_commutator (actual rows=0 loops=1)
3021-
Delete on _hyper_39_79_chunk test_commutator_1
3022-
-> Seq Scan on _hyper_39_79_chunk test_commutator_1 (actual rows=1 loops=1)
3023+
-> Delete on test_pushdown (actual rows=0 loops=1)
3024+
Delete on _hyper_39_79_chunk test_pushdown_1
3025+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=1 loops=1)
30233026
Filter: (device > 'b'::text)
30243027
(7 rows)
30253028

3026-
BEGIN; EXPLAIN (costs off, timing off, summary off, analyze) DELETE FROM test_commutator WHERE 'b' < device; ROLLBACK;
3027-
QUERY PLAN
3028-
--------------------------------------------------------------------------------------
3029+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE device = CURRENT_USER; ROLLBACK;
3030+
QUERY PLAN
3031+
------------------------------------------------------------------------------------------
3032+
Custom Scan (HypertableModify) (actual rows=0 loops=1)
3033+
-> Delete on test_pushdown (actual rows=0 loops=1)
3034+
Delete on _hyper_39_79_chunk test_pushdown_1
3035+
-> Custom Scan (ChunkAppend) on test_pushdown (actual rows=0 loops=1)
3036+
Chunks excluded during startup: 0
3037+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=0 loops=1)
3038+
Filter: (device = CURRENT_USER)
3039+
(7 rows)
3040+
3041+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE 'b' < device; ROLLBACK;
3042+
QUERY PLAN
3043+
------------------------------------------------------------------------------------
30293044
Custom Scan (HypertableModify) (actual rows=0 loops=1)
30303045
Batches decompressed: 1
30313046
Tuples decompressed: 1
3032-
-> Delete on test_commutator (actual rows=0 loops=1)
3033-
Delete on _hyper_39_79_chunk test_commutator_1
3034-
-> Seq Scan on _hyper_39_79_chunk test_commutator_1 (actual rows=1 loops=1)
3047+
-> Delete on test_pushdown (actual rows=0 loops=1)
3048+
Delete on _hyper_39_79_chunk test_pushdown_1
3049+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=1 loops=1)
30353050
Filter: ('b'::text < device)
30363051
(7 rows)
30373052

3038-
BEGIN; EXPLAIN (costs off, timing off, summary off, analyze) DELETE FROM test_commutator WHERE 'b' <= device; ROLLBACK;
3039-
QUERY PLAN
3040-
--------------------------------------------------------------------------------------
3053+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE 'b' <= device; ROLLBACK;
3054+
QUERY PLAN
3055+
------------------------------------------------------------------------------------
30413056
Custom Scan (HypertableModify) (actual rows=0 loops=1)
30423057
Batches decompressed: 2
30433058
Tuples decompressed: 2
3044-
-> Delete on test_commutator (actual rows=0 loops=1)
3045-
Delete on _hyper_39_79_chunk test_commutator_1
3046-
-> Seq Scan on _hyper_39_79_chunk test_commutator_1 (actual rows=2 loops=1)
3059+
-> Delete on test_pushdown (actual rows=0 loops=1)
3060+
Delete on _hyper_39_79_chunk test_pushdown_1
3061+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=2 loops=1)
30473062
Filter: ('b'::text <= device)
30483063
(7 rows)
30493064

3065+
-- cant pushdown OR atm
3066+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE device = 'a' OR device = 'b'; ROLLBACK;
3067+
QUERY PLAN
3068+
------------------------------------------------------------------------------------
3069+
Custom Scan (HypertableModify) (actual rows=0 loops=1)
3070+
Batches decompressed: 3
3071+
Tuples decompressed: 3
3072+
-> Delete on test_pushdown (actual rows=0 loops=1)
3073+
Delete on _hyper_39_79_chunk test_pushdown_1
3074+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=2 loops=1)
3075+
Filter: ((device = 'a'::text) OR (device = 'b'::text))
3076+
Rows Removed by Filter: 1
3077+
(8 rows)
3078+
3079+
-- test stable function
3080+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE time = timestamptz('2020-01-01 05:00'); ROLLBACK;
3081+
QUERY PLAN
3082+
-------------------------------------------------------------------------------------------
3083+
Custom Scan (HypertableModify) (actual rows=0 loops=1)
3084+
Batches decompressed: 1
3085+
Tuples decompressed: 1
3086+
-> Delete on test_pushdown (actual rows=0 loops=1)
3087+
Delete on _hyper_39_79_chunk test_pushdown_1
3088+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=1 loops=1)
3089+
Filter: ("time" = 'Wed Jan 01 05:00:00 2020 PST'::timestamp with time zone)
3090+
(7 rows)
3091+
3092+
-- test sqlvaluefunction
3093+
BEGIN; :EXPLAIN DELETE FROM test_pushdown WHERE device = substring(CURRENT_USER,length(CURRENT_USER)+1) || 'c'; ROLLBACK;
3094+
QUERY PLAN
3095+
-----------------------------------------------------------------------------------------------------------------------------
3096+
Custom Scan (HypertableModify) (actual rows=0 loops=1)
3097+
Batches decompressed: 1
3098+
Tuples decompressed: 1
3099+
-> Delete on test_pushdown (actual rows=0 loops=1)
3100+
Delete on _hyper_39_79_chunk test_pushdown_1
3101+
-> Custom Scan (ChunkAppend) on test_pushdown (actual rows=1 loops=1)
3102+
Chunks excluded during startup: 0
3103+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=1 loops=1)
3104+
Filter: (device = ("substring"((CURRENT_USER)::text, (length((CURRENT_USER)::text) + 1)) || 'c'::text))
3105+
(9 rows)
3106+
3107+
-- no filtering in decompression
3108+
BEGIN; :EXPLAIN DELETE FROM test_pushdown p USING devices d WHERE p.device=d.device; ROLLBACK;
3109+
QUERY PLAN
3110+
------------------------------------------------------------------------------------
3111+
Custom Scan (HypertableModify) (actual rows=0 loops=1)
3112+
Batches decompressed: 3
3113+
Tuples decompressed: 3
3114+
-> Delete on test_pushdown p (actual rows=0 loops=1)
3115+
Delete on _hyper_39_79_chunk p_1
3116+
-> Merge Join (actual rows=3 loops=1)
3117+
Merge Cond: (p_1.device = d.device)
3118+
-> Sort (actual rows=3 loops=1)
3119+
Sort Key: p_1.device
3120+
Sort Method: quicksort
3121+
-> Seq Scan on _hyper_39_79_chunk p_1 (actual rows=3 loops=1)
3122+
-> Sort (actual rows=3 loops=1)
3123+
Sort Key: d.device
3124+
Sort Method: quicksort
3125+
-> Seq Scan on devices d (actual rows=3 loops=1)
3126+
(15 rows)
3127+
3128+
-- can filter in decompression even before executing join
3129+
BEGIN; :EXPLAIN DELETE FROM test_pushdown p USING devices d WHERE p.device=d.device AND d.device ='b' ; ROLLBACK;
3130+
QUERY PLAN
3131+
------------------------------------------------------------------------------------
3132+
Custom Scan (HypertableModify) (actual rows=0 loops=1)
3133+
Batches decompressed: 1
3134+
Tuples decompressed: 1
3135+
-> Delete on test_pushdown p (actual rows=0 loops=1)
3136+
Delete on _hyper_39_79_chunk p_1
3137+
-> Nested Loop (actual rows=1 loops=1)
3138+
-> Seq Scan on devices d (actual rows=1 loops=1)
3139+
Filter: (device = 'b'::text)
3140+
Rows Removed by Filter: 2
3141+
-> Materialize (actual rows=1 loops=1)
3142+
-> Seq Scan on _hyper_39_79_chunk p_1 (actual rows=1 loops=1)
3143+
Filter: (device = 'b'::text)
3144+
(12 rows)
3145+
3146+
-- test prepared statement
3147+
PREPARE q1(text) AS DELETE FROM test_pushdown WHERE device = $1;
3148+
BEGIN; :EXPLAIN EXECUTE q1('a'); ROLLBACK;
3149+
QUERY PLAN
3150+
------------------------------------------------------------------------------------
3151+
Custom Scan (HypertableModify) (actual rows=0 loops=1)
3152+
Batches decompressed: 1
3153+
Tuples decompressed: 1
3154+
-> Delete on test_pushdown (actual rows=0 loops=1)
3155+
Delete on _hyper_39_79_chunk test_pushdown_1
3156+
-> Seq Scan on _hyper_39_79_chunk test_pushdown_1 (actual rows=1 loops=1)
3157+
Filter: (device = 'a'::text)
3158+
(7 rows)
3159+

0 commit comments

Comments
 (0)