mirror of
https://github.com/timescale/timescaledb.git
synced 2025-05-17 11:03:36 +08:00
Reduce decompressions for compressed UPDATE/DELETE
Only decompress batches for compressed UPDATE/DELETE when the batch actually has tuples that match the query constraints. This will work even for columns we have no metadata on.
This commit is contained in:
parent
c10fae76dd
commit
1e04331615
1
.unreleased/pr_7101
Normal file
1
.unreleased/pr_7101
Normal file
@ -0,0 +1 @@
|
|||||||
|
Implements: #7101 Reduce decompressions for compressed UPDATE/DELETE
|
13
src/guc.c
13
src/guc.c
@ -69,6 +69,7 @@ TSDLLEXPORT bool ts_guc_enable_cagg_watermark_constify = true;
|
|||||||
TSDLLEXPORT int ts_guc_cagg_max_individual_materializations = 10;
|
TSDLLEXPORT int ts_guc_cagg_max_individual_materializations = 10;
|
||||||
bool ts_guc_enable_osm_reads = true;
|
bool ts_guc_enable_osm_reads = true;
|
||||||
TSDLLEXPORT bool ts_guc_enable_dml_decompression = true;
|
TSDLLEXPORT bool ts_guc_enable_dml_decompression = true;
|
||||||
|
TSDLLEXPORT bool ts_guc_enable_dml_decompression_tuple_filtering = true;
|
||||||
TSDLLEXPORT int ts_guc_max_tuples_decompressed_per_dml = 100000;
|
TSDLLEXPORT int ts_guc_max_tuples_decompressed_per_dml = 100000;
|
||||||
TSDLLEXPORT bool ts_guc_enable_transparent_decompression = true;
|
TSDLLEXPORT bool ts_guc_enable_transparent_decompression = true;
|
||||||
TSDLLEXPORT bool ts_guc_enable_compression_wal_markers = false;
|
TSDLLEXPORT bool ts_guc_enable_compression_wal_markers = false;
|
||||||
@ -437,6 +438,18 @@ _guc_init(void)
|
|||||||
NULL,
|
NULL,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
DefineCustomBoolVariable(MAKE_EXTOPTION("enable_dml_decompression_tuple_filtering"),
|
||||||
|
"Enable DML decompression tuple filtering",
|
||||||
|
"Recheck tuples during DML decompression to only decompress batches "
|
||||||
|
"with matching tuples",
|
||||||
|
&ts_guc_enable_dml_decompression_tuple_filtering,
|
||||||
|
true,
|
||||||
|
PGC_USERSET,
|
||||||
|
0,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
DefineCustomIntVariable(MAKE_EXTOPTION("max_tuples_decompressed_per_dml_transaction"),
|
DefineCustomIntVariable(MAKE_EXTOPTION("max_tuples_decompressed_per_dml_transaction"),
|
||||||
"The max number of tuples that can be decompressed during an "
|
"The max number of tuples that can be decompressed during an "
|
||||||
"INSERT, UPDATE, or DELETE.",
|
"INSERT, UPDATE, or DELETE.",
|
||||||
|
@ -29,6 +29,7 @@ extern bool ts_guc_enable_now_constify;
|
|||||||
extern TSDLLEXPORT bool ts_guc_enable_cagg_watermark_constify;
|
extern TSDLLEXPORT bool ts_guc_enable_cagg_watermark_constify;
|
||||||
extern bool ts_guc_enable_osm_reads;
|
extern bool ts_guc_enable_osm_reads;
|
||||||
extern TSDLLEXPORT bool ts_guc_enable_dml_decompression;
|
extern TSDLLEXPORT bool ts_guc_enable_dml_decompression;
|
||||||
|
extern TSDLLEXPORT bool ts_guc_enable_dml_decompression_tuple_filtering;
|
||||||
extern TSDLLEXPORT int ts_guc_max_tuples_decompressed_per_dml;
|
extern TSDLLEXPORT int ts_guc_max_tuples_decompressed_per_dml;
|
||||||
extern TSDLLEXPORT bool ts_guc_enable_transparent_decompression;
|
extern TSDLLEXPORT bool ts_guc_enable_transparent_decompression;
|
||||||
extern TSDLLEXPORT bool ts_guc_enable_compression_wal_markers;
|
extern TSDLLEXPORT bool ts_guc_enable_compression_wal_markers;
|
||||||
|
@ -42,6 +42,7 @@ decompress_batches_seqscan(Relation in_rel, Relation out_rel, Snapshot snapshot,
|
|||||||
|
|
||||||
static bool batch_matches(RowDecompressor *decompressor, ScanKeyData *scankeys, int num_scankeys);
|
static bool batch_matches(RowDecompressor *decompressor, ScanKeyData *scankeys, int num_scankeys);
|
||||||
static void process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates,
|
static void process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates,
|
||||||
|
ScanKeyData **mem_scankeys, int *num_mem_scankeys,
|
||||||
List **heap_filters, List **index_filters, List **is_null);
|
List **heap_filters, List **index_filters, List **is_null);
|
||||||
static Relation find_matching_index(Relation comp_chunk_rel, List **index_filters,
|
static Relation find_matching_index(Relation comp_chunk_rel, List **index_filters,
|
||||||
List **heap_filters);
|
List **heap_filters);
|
||||||
@ -89,13 +90,17 @@ decompress_batches_for_insert(const ChunkInsertState *cis, TupleTableSlot *slot)
|
|||||||
struct decompress_batches_stats stats;
|
struct decompress_batches_stats stats;
|
||||||
|
|
||||||
/* the scan keys used for in memory tests of the decompressed tuples */
|
/* the scan keys used for in memory tests of the decompressed tuples */
|
||||||
int num_mem_scankeys;
|
int num_mem_scankeys = 0;
|
||||||
ScanKeyData *mem_scankeys = build_scankeys_for_uncompressed(cis->hypertable_relid,
|
ScanKeyData *mem_scankeys = NULL;
|
||||||
settings,
|
if (ts_guc_enable_dml_decompression_tuple_filtering)
|
||||||
out_rel,
|
{
|
||||||
key_columns,
|
mem_scankeys = build_mem_scankeys_from_slot(cis->hypertable_relid,
|
||||||
slot,
|
settings,
|
||||||
&num_mem_scankeys);
|
out_rel,
|
||||||
|
key_columns,
|
||||||
|
slot,
|
||||||
|
&num_mem_scankeys);
|
||||||
|
}
|
||||||
|
|
||||||
int num_index_scankeys;
|
int num_index_scankeys;
|
||||||
Relation index_rel = NULL;
|
Relation index_rel = NULL;
|
||||||
@ -211,11 +216,20 @@ decompress_batches_for_update_delete(HypertableModifyState *ht_state, Chunk *chu
|
|||||||
ScanKeyData *index_scankeys = NULL;
|
ScanKeyData *index_scankeys = NULL;
|
||||||
int num_index_scankeys = 0;
|
int num_index_scankeys = 0;
|
||||||
struct decompress_batches_stats stats;
|
struct decompress_batches_stats stats;
|
||||||
|
int num_mem_scankeys = 0;
|
||||||
|
ScanKeyData *mem_scankeys = NULL;
|
||||||
|
|
||||||
comp_chunk = ts_chunk_get_by_id(chunk->fd.compressed_chunk_id, true);
|
comp_chunk = ts_chunk_get_by_id(chunk->fd.compressed_chunk_id, true);
|
||||||
CompressionSettings *settings = ts_compression_settings_get(comp_chunk->table_id);
|
CompressionSettings *settings = ts_compression_settings_get(comp_chunk->table_id);
|
||||||
|
|
||||||
process_predicates(chunk, settings, predicates, &heap_filters, &index_filters, &is_null);
|
process_predicates(chunk,
|
||||||
|
settings,
|
||||||
|
predicates,
|
||||||
|
&mem_scankeys,
|
||||||
|
&num_mem_scankeys,
|
||||||
|
&heap_filters,
|
||||||
|
&index_filters,
|
||||||
|
&is_null);
|
||||||
|
|
||||||
chunk_rel = table_open(chunk->table_id, RowExclusiveLock);
|
chunk_rel = table_open(chunk->table_id, RowExclusiveLock);
|
||||||
comp_chunk_rel = table_open(comp_chunk->table_id, RowExclusiveLock);
|
comp_chunk_rel = table_open(comp_chunk->table_id, RowExclusiveLock);
|
||||||
@ -244,8 +258,8 @@ decompress_batches_for_update_delete(HypertableModifyState *ht_state, Chunk *chu
|
|||||||
num_index_scankeys,
|
num_index_scankeys,
|
||||||
scankeys,
|
scankeys,
|
||||||
num_scankeys,
|
num_scankeys,
|
||||||
NULL,
|
mem_scankeys,
|
||||||
0,
|
num_mem_scankeys,
|
||||||
null_columns,
|
null_columns,
|
||||||
is_null);
|
is_null);
|
||||||
/* close the selected index */
|
/* close the selected index */
|
||||||
@ -258,8 +272,8 @@ decompress_batches_for_update_delete(HypertableModifyState *ht_state, Chunk *chu
|
|||||||
GetTransactionSnapshot(),
|
GetTransactionSnapshot(),
|
||||||
scankeys,
|
scankeys,
|
||||||
num_scankeys,
|
num_scankeys,
|
||||||
NULL,
|
mem_scankeys,
|
||||||
0,
|
num_mem_scankeys,
|
||||||
null_columns,
|
null_columns,
|
||||||
is_null);
|
is_null);
|
||||||
}
|
}
|
||||||
@ -390,6 +404,12 @@ decompress_batches_indexscan(Relation in_rel, Relation out_rel, Relation index_r
|
|||||||
decompressor.compressed_datums,
|
decompressor.compressed_datums,
|
||||||
decompressor.compressed_is_nulls);
|
decompressor.compressed_is_nulls);
|
||||||
|
|
||||||
|
if (num_mem_scankeys && !batch_matches(&decompressor, mem_scankeys, num_mem_scankeys))
|
||||||
|
{
|
||||||
|
row_decompressor_reset(&decompressor);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
write_logical_replication_msg_decompression_start();
|
write_logical_replication_msg_decompression_start();
|
||||||
result = delete_compressed_tuple(&decompressor, snapshot, compressed_tuple);
|
result = delete_compressed_tuple(&decompressor, snapshot, compressed_tuple);
|
||||||
/* skip reporting error if isolation level is < Repeatable Read
|
/* skip reporting error if isolation level is < Repeatable Read
|
||||||
@ -791,10 +811,17 @@ compressed_insert_key_columns(Relation relation)
|
|||||||
* filters are put into heap_filters list.
|
* filters are put into heap_filters list.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates, List **heap_filters,
|
process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates,
|
||||||
|
ScanKeyData **mem_scankeys, int *num_mem_scankeys, List **heap_filters,
|
||||||
List **index_filters, List **is_null)
|
List **index_filters, List **is_null)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
if (ts_guc_enable_dml_decompression_tuple_filtering)
|
||||||
|
{
|
||||||
|
*mem_scankeys = palloc0(sizeof(ScanKeyData) * list_length(predicates));
|
||||||
|
}
|
||||||
|
*num_mem_scankeys = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We dont want to forward boundParams from the execution state here
|
* We dont want to forward boundParams from the execution state here
|
||||||
* as we dont want to constify join params in the predicates.
|
* as we dont want to constify join params in the predicates.
|
||||||
@ -837,6 +864,7 @@ process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates, L
|
|||||||
column_name = get_attname(ch->table_id, var->varattno, false);
|
column_name = get_attname(ch->table_id, var->varattno, false);
|
||||||
TypeCacheEntry *tce = lookup_type_cache(var->vartype, TYPECACHE_BTREE_OPFAMILY);
|
TypeCacheEntry *tce = lookup_type_cache(var->vartype, TYPECACHE_BTREE_OPFAMILY);
|
||||||
int op_strategy = get_op_opfamily_strategy(opno, tce->btree_opf);
|
int op_strategy = get_op_opfamily_strategy(opno, tce->btree_opf);
|
||||||
|
|
||||||
if (ts_array_is_member(settings->fd.segmentby, column_name))
|
if (ts_array_is_member(settings->fd.segmentby, column_name))
|
||||||
{
|
{
|
||||||
switch (op_strategy)
|
switch (op_strategy)
|
||||||
@ -864,6 +892,21 @@ process_predicates(Chunk *ch, CompressionSettings *settings, List *predicates, L
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Segmentby columns are checked as part of batch scan so no need to redo the check.
|
||||||
|
*/
|
||||||
|
if (ts_guc_enable_dml_decompression_tuple_filtering)
|
||||||
|
{
|
||||||
|
ScanKeyEntryInitialize(&(*mem_scankeys)[(*num_mem_scankeys)++],
|
||||||
|
arg_value->constisnull ? SK_ISNULL : 0,
|
||||||
|
var->varattno,
|
||||||
|
op_strategy,
|
||||||
|
arg_value->consttype,
|
||||||
|
arg_value->constcollid,
|
||||||
|
opcode,
|
||||||
|
arg_value->constisnull ? 0 : arg_value->constvalue);
|
||||||
|
}
|
||||||
|
|
||||||
int min_attno = compressed_column_metadata_attno(settings,
|
int min_attno = compressed_column_metadata_attno(settings,
|
||||||
ch->table_id,
|
ch->table_id,
|
||||||
var->varattno,
|
var->varattno,
|
||||||
|
@ -10,9 +10,9 @@
|
|||||||
|
|
||||||
#include "ts_catalog/compression_settings.h"
|
#include "ts_catalog/compression_settings.h"
|
||||||
|
|
||||||
ScanKeyData *build_scankeys_for_uncompressed(Oid ht_relid, CompressionSettings *settings,
|
ScanKeyData *build_mem_scankeys_from_slot(Oid ht_relid, CompressionSettings *settings,
|
||||||
Relation out_rel, Bitmapset *key_columns,
|
Relation out_rel, Bitmapset *key_columns,
|
||||||
TupleTableSlot *slot, int *num_scankeys);
|
TupleTableSlot *slot, int *num_scankeys);
|
||||||
ScanKeyData *build_index_scankeys(Relation index_rel, List *index_filters, int *num_scankeys);
|
ScanKeyData *build_index_scankeys(Relation index_rel, List *index_filters, int *num_scankeys);
|
||||||
ScanKeyData *build_index_scankeys_using_slot(Oid hypertable_relid, Relation in_rel,
|
ScanKeyData *build_index_scankeys_using_slot(Oid hypertable_relid, Relation in_rel,
|
||||||
Relation out_rel, Bitmapset *key_columns,
|
Relation out_rel, Bitmapset *key_columns,
|
||||||
@ -23,7 +23,3 @@ ScanKeyData *build_heap_scankeys(Oid hypertable_relid, Relation in_rel, Relation
|
|||||||
Bitmapset **null_columns, TupleTableSlot *slot, int *num_scankeys);
|
Bitmapset **null_columns, TupleTableSlot *slot, int *num_scankeys);
|
||||||
ScanKeyData *build_update_delete_scankeys(Relation in_rel, List *heap_filters, int *num_scankeys,
|
ScanKeyData *build_update_delete_scankeys(Relation in_rel, List *heap_filters, int *num_scankeys,
|
||||||
Bitmapset **null_columns);
|
Bitmapset **null_columns);
|
||||||
int create_segment_filter_scankey(Relation in_rel, char *segment_filter_col_name,
|
|
||||||
StrategyNumber strategy, Oid subtype, ScanKeyData *scankeys,
|
|
||||||
int num_scankeys, Bitmapset **null_columns, Datum value,
|
|
||||||
bool is_null_check, bool is_array_op);
|
|
||||||
|
@ -16,6 +16,11 @@
|
|||||||
#include "ts_catalog/array_utils.h"
|
#include "ts_catalog/array_utils.h"
|
||||||
|
|
||||||
static Oid deduce_filter_subtype(BatchFilter *filter, Oid att_typoid);
|
static Oid deduce_filter_subtype(BatchFilter *filter, Oid att_typoid);
|
||||||
|
static int create_segment_filter_scankey(Relation in_rel, char *segment_filter_col_name,
|
||||||
|
StrategyNumber strategy, Oid subtype,
|
||||||
|
ScanKeyData *scankeys, int num_scankeys,
|
||||||
|
Bitmapset **null_columns, Datum value, bool is_null_check,
|
||||||
|
bool is_array_op);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build scankeys for decompressed tuple to check if it is part of the batch.
|
* Build scankeys for decompressed tuple to check if it is part of the batch.
|
||||||
@ -23,12 +28,13 @@ static Oid deduce_filter_subtype(BatchFilter *filter, Oid att_typoid);
|
|||||||
* The key_columns are the columns of the uncompressed chunk.
|
* The key_columns are the columns of the uncompressed chunk.
|
||||||
*/
|
*/
|
||||||
ScanKeyData *
|
ScanKeyData *
|
||||||
build_scankeys_for_uncompressed(Oid ht_relid, CompressionSettings *settings, Relation out_rel,
|
build_mem_scankeys_from_slot(Oid ht_relid, CompressionSettings *settings, Relation out_rel,
|
||||||
Bitmapset *key_columns, TupleTableSlot *slot, int *num_scankeys)
|
Bitmapset *key_columns, TupleTableSlot *slot, int *num_scankeys)
|
||||||
{
|
{
|
||||||
ScanKeyData *scankeys = NULL;
|
ScanKeyData *scankeys = NULL;
|
||||||
int key_index = 0;
|
int key_index = 0;
|
||||||
TupleDesc out_desc = RelationGetDescr(out_rel);
|
TupleDesc out_desc = RelationGetDescr(out_rel);
|
||||||
|
TupleDesc in_desc = slot->tts_tupleDescriptor;
|
||||||
|
|
||||||
if (bms_is_empty(key_columns))
|
if (bms_is_empty(key_columns))
|
||||||
{
|
{
|
||||||
@ -93,8 +99,8 @@ build_scankeys_for_uncompressed(Oid ht_relid, CompressionSettings *settings, Rel
|
|||||||
isnull ? SK_ISNULL | SK_SEARCHNULL : 0,
|
isnull ? SK_ISNULL | SK_SEARCHNULL : 0,
|
||||||
attno,
|
attno,
|
||||||
BTEqualStrategyNumber,
|
BTEqualStrategyNumber,
|
||||||
InvalidOid,
|
in_desc->attrs[AttrNumberGetAttrOffset(ht_attno)].atttypid,
|
||||||
out_desc->attrs[AttrNumberGetAttrOffset(attno)].attcollation,
|
in_desc->attrs[AttrNumberGetAttrOffset(ht_attno)].attcollation,
|
||||||
get_opcode(opr),
|
get_opcode(opr),
|
||||||
isnull ? 0 : value);
|
isnull ? 0 : value);
|
||||||
}
|
}
|
||||||
@ -437,7 +443,7 @@ build_update_delete_scankeys(Relation in_rel, List *heap_filters, int *num_scank
|
|||||||
return scankeys;
|
return scankeys;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
static int
|
||||||
create_segment_filter_scankey(Relation in_rel, char *segment_filter_col_name,
|
create_segment_filter_scankey(Relation in_rel, char *segment_filter_col_name,
|
||||||
StrategyNumber strategy, Oid subtype, ScanKeyData *scankeys,
|
StrategyNumber strategy, Oid subtype, ScanKeyData *scankeys,
|
||||||
int num_scankeys, Bitmapset **null_columns, Datum value,
|
int num_scankeys, Bitmapset **null_columns, Datum value,
|
||||||
|
@ -122,12 +122,13 @@ FROM compressed_chunk_info_view
|
|||||||
WHERE hypertable_name = 'sample_table' ORDER BY chunk_name;
|
WHERE hypertable_name = 'sample_table' ORDER BY chunk_name;
|
||||||
chunk_status | CHUNK_NAME
|
chunk_status | CHUNK_NAME
|
||||||
--------------+------------------
|
--------------+------------------
|
||||||
9 | _hyper_1_1_chunk
|
1 | _hyper_1_1_chunk
|
||||||
9 | _hyper_1_2_chunk
|
9 | _hyper_1_2_chunk
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
-- recompress the partial chunks
|
-- recompress the partial chunks
|
||||||
SELECT compress_chunk('_timescaledb_internal._hyper_1_1_chunk');
|
SELECT compress_chunk('_timescaledb_internal._hyper_1_1_chunk');
|
||||||
|
NOTICE: chunk "_hyper_1_1_chunk" is already compressed
|
||||||
compress_chunk
|
compress_chunk
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
_timescaledb_internal._hyper_1_1_chunk
|
_timescaledb_internal._hyper_1_1_chunk
|
||||||
@ -173,12 +174,13 @@ FROM compressed_chunk_info_view
|
|||||||
WHERE hypertable_name = 'sample_table' ORDER BY chunk_name;
|
WHERE hypertable_name = 'sample_table' ORDER BY chunk_name;
|
||||||
chunk_status | CHUNK_NAME
|
chunk_status | CHUNK_NAME
|
||||||
--------------+------------------
|
--------------+------------------
|
||||||
9 | _hyper_1_1_chunk
|
1 | _hyper_1_1_chunk
|
||||||
9 | _hyper_1_2_chunk
|
9 | _hyper_1_2_chunk
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
-- recompress the paritial chunks
|
-- recompress the paritial chunks
|
||||||
SELECT compress_chunk('_timescaledb_internal._hyper_1_1_chunk');
|
SELECT compress_chunk('_timescaledb_internal._hyper_1_1_chunk');
|
||||||
|
NOTICE: chunk "_hyper_1_1_chunk" is already compressed
|
||||||
compress_chunk
|
compress_chunk
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
_timescaledb_internal._hyper_1_1_chunk
|
_timescaledb_internal._hyper_1_1_chunk
|
||||||
|
@ -258,3 +258,152 @@ QUERY PLAN
|
|||||||
-> Result (actual rows=1 loops=1)
|
-> Result (actual rows=1 loops=1)
|
||||||
(10 rows)
|
(10 rows)
|
||||||
|
|
||||||
|
-- no decompression cause no match in batch
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 0; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
-> Update on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Update on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Result (actual rows=0 loops=1)
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=0 loops=1)
|
||||||
|
Filter: (value = '0'::double precision)
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
-> Update on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Update on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Result (actual rows=0 loops=1)
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=0 loops=1)
|
||||||
|
Filter: ((value = '0'::double precision) AND (device = 'd1'::text))
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
-- 1 batch decompression
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 2300; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 1
|
||||||
|
Tuples decompressed: 1000
|
||||||
|
-> Update on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Update on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Result (actual rows=1 loops=1)
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=1 loops=1)
|
||||||
|
Filter: (value = '2300'::double precision)
|
||||||
|
Rows Removed by Filter: 999
|
||||||
|
(9 rows)
|
||||||
|
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value > 3100 AND value < 3200; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 1
|
||||||
|
Tuples decompressed: 1000
|
||||||
|
-> Update on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Update on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Result (actual rows=99 loops=1)
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=99 loops=1)
|
||||||
|
Filter: ((value > '3100'::double precision) AND (value < '3200'::double precision))
|
||||||
|
Rows Removed by Filter: 901
|
||||||
|
(9 rows)
|
||||||
|
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value BETWEEN 3100 AND 3200; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 1
|
||||||
|
Tuples decompressed: 1000
|
||||||
|
-> Update on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Update on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Result (actual rows=101 loops=1)
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=101 loops=1)
|
||||||
|
Filter: ((value >= '3100'::double precision) AND (value <= '3200'::double precision))
|
||||||
|
Rows Removed by Filter: 899
|
||||||
|
(9 rows)
|
||||||
|
|
||||||
|
-- check GUC is working, should be 6 batches and 6000 tuples decompresed
|
||||||
|
SET timescaledb.enable_dml_decompression_tuple_filtering TO off;
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 6
|
||||||
|
Tuples decompressed: 6000
|
||||||
|
-> Update on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Update on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Result (actual rows=0 loops=1)
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=0 loops=1)
|
||||||
|
Filter: ((value = '0'::double precision) AND (device = 'd1'::text))
|
||||||
|
Rows Removed by Filter: 6000
|
||||||
|
(9 rows)
|
||||||
|
|
||||||
|
RESET timescaledb.enable_dml_decompression_tuple_filtering;
|
||||||
|
-- no decompression cause no match in batch
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 0; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
-> Delete on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Delete on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=0 loops=1)
|
||||||
|
Filter: (value = '0'::double precision)
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
-> Delete on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Delete on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=0 loops=1)
|
||||||
|
Filter: ((value = '0'::double precision) AND (device = 'd1'::text))
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- 1 batch decompression
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 2300; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 1
|
||||||
|
Tuples decompressed: 1000
|
||||||
|
-> Delete on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Delete on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=1 loops=1)
|
||||||
|
Filter: (value = '2300'::double precision)
|
||||||
|
Rows Removed by Filter: 999
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value > 3100 AND value < 3200; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 1
|
||||||
|
Tuples decompressed: 1000
|
||||||
|
-> Delete on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Delete on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=99 loops=1)
|
||||||
|
Filter: ((value > '3100'::double precision) AND (value < '3200'::double precision))
|
||||||
|
Rows Removed by Filter: 901
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value BETWEEN 3100 AND 3200; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 1
|
||||||
|
Tuples decompressed: 1000
|
||||||
|
-> Delete on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Delete on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=101 loops=1)
|
||||||
|
Filter: ((value >= '3100'::double precision) AND (value <= '3200'::double precision))
|
||||||
|
Rows Removed by Filter: 899
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
-- check GUC is working, should be 6 batches and 6000 tuples decompresed
|
||||||
|
SET timescaledb.enable_dml_decompression_tuple_filtering TO off;
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
QUERY PLAN
|
||||||
|
Custom Scan (HypertableModify) (actual rows=0 loops=1)
|
||||||
|
Batches decompressed: 6
|
||||||
|
Tuples decompressed: 6000
|
||||||
|
-> Delete on lazy_decompress (actual rows=0 loops=1)
|
||||||
|
Delete on _hyper_X_X_chunk lazy_decompress_1
|
||||||
|
-> Seq Scan on _hyper_X_X_chunk lazy_decompress_1 (actual rows=0 loops=1)
|
||||||
|
Filter: ((value = '0'::double precision) AND (device = 'd1'::text))
|
||||||
|
Rows Removed by Filter: 6000
|
||||||
|
(8 rows)
|
||||||
|
|
||||||
|
RESET timescaledb.enable_dml_decompression_tuple_filtering;
|
||||||
|
DROP TABLE lazy_decompress;
|
||||||
|
@ -159,3 +159,32 @@ BEGIN; :ANALYZE INSERT INTO lazy_decompress SELECT '2024-01-01 0:00:00.5','d1',r
|
|||||||
BEGIN; :ANALYZE INSERT INTO lazy_decompress SELECT '2024-01-01 0:00:00.5','d1',random() ON CONFLICT(time,device) DO UPDATE SET value=EXCLUDED.value; ROLLBACK;
|
BEGIN; :ANALYZE INSERT INTO lazy_decompress SELECT '2024-01-01 0:00:00.5','d1',random() ON CONFLICT(time,device) DO UPDATE SET value=EXCLUDED.value; ROLLBACK;
|
||||||
-- should decompress 1 batch cause there is match
|
-- should decompress 1 batch cause there is match
|
||||||
BEGIN; :ANALYZE INSERT INTO lazy_decompress SELECT '2024-01-01 0:00:01','d1',random() ON CONFLICT DO NOTHING; ROLLBACK;
|
BEGIN; :ANALYZE INSERT INTO lazy_decompress SELECT '2024-01-01 0:00:01','d1',random() ON CONFLICT DO NOTHING; ROLLBACK;
|
||||||
|
|
||||||
|
-- no decompression cause no match in batch
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 0; ROLLBACK;
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
-- 1 batch decompression
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 2300; ROLLBACK;
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value > 3100 AND value < 3200; ROLLBACK;
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value BETWEEN 3100 AND 3200; ROLLBACK;
|
||||||
|
|
||||||
|
-- check GUC is working, should be 6 batches and 6000 tuples decompresed
|
||||||
|
SET timescaledb.enable_dml_decompression_tuple_filtering TO off;
|
||||||
|
BEGIN; :ANALYZE UPDATE lazy_decompress SET value = 3.14 WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
RESET timescaledb.enable_dml_decompression_tuple_filtering;
|
||||||
|
|
||||||
|
-- no decompression cause no match in batch
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 0; ROLLBACK;
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
-- 1 batch decompression
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 2300; ROLLBACK;
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value > 3100 AND value < 3200; ROLLBACK;
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value BETWEEN 3100 AND 3200; ROLLBACK;
|
||||||
|
|
||||||
|
-- check GUC is working, should be 6 batches and 6000 tuples decompresed
|
||||||
|
SET timescaledb.enable_dml_decompression_tuple_filtering TO off;
|
||||||
|
BEGIN; :ANALYZE DELETE FROM lazy_decompress WHERE value = 0 AND device='d1'; ROLLBACK;
|
||||||
|
RESET timescaledb.enable_dml_decompression_tuple_filtering;
|
||||||
|
|
||||||
|
DROP TABLE lazy_decompress;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user