timescaledb/tsl/test/sql/hypercore_delete.sql
Mats Kindahl 406901d838 Rename files using "hyperstore" to use "hypercore"
Files and directories using "hyperstore" as part of the name is moved
to the new name using "hypercore".
2024-10-16 13:13:34 +02:00

130 lines
5.2 KiB
SQL

-- This file and its contents are licensed under the Timescale License.
-- Please see the included NOTICE for copyright information and
-- LICENSE-TIMESCALE for a copy of the license.
select setseed(0.3);
create table devices (id int, primary key (id));
create table locations (id int, primary key (id));
create table metrics (time timestamptz, device int, location int, temp float);
select create_hypertable('metrics', 'time', create_default_indexes => false);
insert into devices values (1), (2);
insert into locations values (1), (2);
insert into metrics values ('2024-01-01', 1, 1, 1.0), ('2024-01-01', 2, 2, 2.0), ('2024-01-02', 1, 2, 3.0), ('2024-01-02', 2, 2, 4.0);
-- Add foreign key constraint to test cascading deletes
alter table metrics add constraint device_fk foreign key (device) references devices (id) on delete cascade;
alter table metrics set (timescaledb.compress_segmentby = 'device');
-- Make the one chunk a Hyperstore
select ch as chunk from show_chunks('metrics') ch limit 1 \gset
alter table :chunk set access method hyperstore;
-- Show that all data is compressed
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics order by time, device;
\set ON_ERROR_STOP 0
-- It should not be possible to do non-whole segment deletes
delete from :chunk where location=1;
delete from :chunk where location=2;
delete from :chunk where device=1 and location=2;
delete from :chunk where temp=1;
\set ON_ERROR_STOP 1
start transaction;
-- Deleting whole segment is OK
delete from :chunk where device=1;
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics order by time, device;
rollback;
start transaction;
-- Deleting multiple whole segments is also OK
delete from :chunk where device in (1,2);
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics order by time, device;
rollback;
start transaction;
-- It is possible to delete by location as long as whole segments are
-- deleted
delete from :chunk where location in (1,2);
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics order by time, device;
rollback;
-- Test delete via hypertable. It will lead to DML decompression, so
-- not whole-segment delete.
start transaction;
delete from metrics where location=1;
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics order by time, device;
rollback;
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics order by time, device;
-----------------------------------------------------
-- Test cascading deletes via foreign key constraint
-----------------------------------------------------
-- Delete from devices table should cascade via foreign key to metrics
-- table. First show that data exists and is compressed
explain
delete from devices where id=2;
start transaction;
delete from devices where id=2;
-- No rows for device 2 should remain
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics where device=2 order by time, device;
rollback;
-----------------------------------------------------
-- Try deletes on bigger data set with full segments
-----------------------------------------------------
insert into devices values (3), (4);
insert into metrics (time, device, location, temp)
select t, ceil(random()*4), ceil(random()*30), random()*40
from generate_series('2024-01-01'::timestamptz, '2024-01-03', '10s') t;
-- Still just one chunk
select count(ch) from show_chunks('metrics') ch;
-- Make sure it is fully compressed
vacuum full metrics;
-- Find the compressed chunk rel
create view compressed_rels as
with reg_chunk as (
select * from _timescaledb_catalog.chunk where compressed_chunk_id IS NOT NULL
)
select format('%I.%I', reg_chunk.schema_name, reg_chunk.table_name)::regclass as relid,
format('%I.%I', cpr_chunk.schema_name, cpr_chunk.table_name)::regclass as compressed_relid
from _timescaledb_catalog.chunk cpr_chunk
inner join reg_chunk on (cpr_chunk.id = reg_chunk.compressed_chunk_id);
select compressed_relid as cchunk from compressed_rels \gset
select _ts_meta_count, device from :cchunk
where device in (1, 2, 3)
order by device, _ts_meta_count;
start transaction;
delete from devices where id=2;
-- No rows for device 2 should remain
select _ts_meta_count, device from :cchunk
where device in (1, 2, 3)
order by device, _ts_meta_count;
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics where device=2 order by time, device;
rollback;
-- Insert non-compressed rows
insert into metrics values ('2024-01-01', 1, 10, 6.0), ('2024-01-01', 2, 12, 7.0), ('2024-01-02', 1, 10, 8.0), ('2024-01-02', 2, 13, 9.0);
start transaction;
-- Delete directly on chunk instead of cascading FK delete
delete from :chunk where device=1;
-- No rows for device 1 should remain, neither compressed nor non-compressed
select _ts_meta_count, device from :cchunk
where device=1
order by device, _ts_meta_count;
select _timescaledb_debug.is_compressed_tid(ctid) as compressed, * from metrics where device=1 order by time, device;
rollback;
select count(*) from metrics;
-- Try deleting on a device that doesn't exist
delete from metrics where device=10;
-- Nothing should be deleted and count() should be the same
select count(*) from metrics;