数据删除 #

一、删除概述 #

1.1 TimescaleDB删除特点 #

text
TimescaleDB删除优势:

分片级别删除
├── drop_chunks快速删除整个分片
├── 比DELETE快得多
└── 自动释放磁盘空间

保留策略
├── 自动删除旧数据
├── 配置数据生命周期
└── 定期自动执行

兼容性
├── 标准DELETE语法
├── 支持条件删除
└── 支持级联删除

1.2 删除方式选择 #

text
删除方式选择:

DELETE
├── 删除特定条件数据
├── 删除少量数据
├── 需要精确控制
└── 性能较低

drop_chunks
├── 删除整个分片
├── 删除大量历史数据
├── 数据生命周期管理
└── 性能极高

TRUNCATE
├── 删除所有数据
├── 保留表结构
└── 最快方式

二、DELETE删除 #

2.1 基本删除 #

sql
-- 创建示例表
CREATE TABLE sensor_data (
    time TIMESTAMPTZ NOT NULL,
    sensor_id INTEGER NOT NULL,
    temperature DOUBLE PRECISION,
    humidity DOUBLE PRECISION
);

SELECT create_hypertable('sensor_data', 'time');

-- 删除特定条件数据
DELETE FROM sensor_data
WHERE sensor_id = 1;

-- 删除时间范围数据
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days';

-- 删除多条件数据
DELETE FROM sensor_data
WHERE sensor_id = 1
  AND time < NOW() - INTERVAL '30 days';

-- 删除NULL值
DELETE FROM sensor_data
WHERE temperature IS NULL;

2.2 返回删除结果 #

sql
-- 返回删除的行
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days'
RETURNING *;

-- 返回特定列
DELETE FROM sensor_data
WHERE sensor_id = 1
RETURNING time, sensor_id, temperature;

-- 统计删除数量
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days';

SELECT 'Deleted ' || ROW_COUNT || ' rows' as result;

2.3 使用子查询删除 #

sql
-- 使用子查询删除
DELETE FROM sensor_data
WHERE sensor_id IN (
    SELECT sensor_id FROM inactive_sensors
);

-- 使用EXISTS删除
DELETE FROM sensor_data sd
WHERE EXISTS (
    SELECT 1 FROM sensor_alerts sa
    WHERE sa.sensor_id = sd.sensor_id
      AND sa.alert_type = 'malfunction'
);

-- 使用JOIN删除
DELETE FROM sensor_data
USING sensor_status ss
WHERE sensor_data.sensor_id = ss.sensor_id
  AND ss.status = 'deleted';

2.4 批量删除 #

sql
-- 分批删除大量数据
DO $$
DECLARE
    batch_size INTEGER := 10000;
    deleted_rows INTEGER;
BEGIN
    LOOP
        DELETE FROM sensor_data
        WHERE time < NOW() - INTERVAL '90 days'
        LIMIT batch_size;
        
        GET DIAGNOSTICS deleted_rows = ROW_COUNT;
        
        EXIT WHEN deleted_rows = 0;
        
        COMMIT;
        RAISE NOTICE 'Deleted % rows', deleted_rows;
    END LOOP;
END $$;

三、drop_chunks删除 #

3.1 基本用法 #

sql
-- 删除90天前的所有分片
SELECT drop_chunks(
    'sensor_data',
    older_than => INTERVAL '90 days'
);

-- 删除指定日期前的分片
SELECT drop_chunks(
    'sensor_data',
    older_than => '2024-01-01'::timestamptz
);

-- 删除指定时间范围
SELECT drop_chunks(
    'sensor_data',
    newer_than => INTERVAL '180 days',
    older_than => INTERVAL '90 days'
);

-- 删除所有分片
SELECT drop_chunks('sensor_data');

3.2 drop_chunks参数 #

sql
-- 完整参数示例
SELECT drop_chunks(
    'sensor_data',                    -- 超表名
    older_than => INTERVAL '90 days', -- 删除此时间之前的分片
    newer_than => NULL,               -- 可选:删除此时间之后的分片
    verbose => TRUE                   -- 显示详细信息
);

-- 查看将被删除的分片(不实际删除)
SELECT 
    chunk_name,
    range_start,
    range_end
FROM timescaledb_information.chunks
WHERE hypertable_name = 'sensor_data'
  AND range_end < NOW() - INTERVAL '90 days';

3.3 drop_chunks优势 #

text
drop_chunks vs DELETE:

drop_chunks
├── 删除整个分片
├── 速度快
├── 立即释放磁盘空间
├── 不产生WAL日志
└── 适合数据生命周期管理

DELETE
├── 逐行删除
├── 速度慢
├── 需要VACUUM释放空间
├── 产生大量WAL日志
└── 适合精确删除

3.4 删除多个超表 #

sql
-- 删除多个超表的旧数据
SELECT drop_chunks(
    ARRAY['sensor_data', 'events', 'logs'],
    older_than => INTERVAL '30 days'
);

-- 查看所有超表
SELECT hypertable_name FROM timescaledb_information.hypertables;

四、保留策略 #

4.1 添加保留策略 #

sql
-- 添加保留策略
SELECT add_retention_policy(
    'sensor_data',
    INTERVAL '90 days'
);

-- 查看保留策略
SELECT 
    job_id,
    application_name,
    schedule_interval,
    config
FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention';

-- 查看策略详情
SELECT * FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention';

4.2 修改保留策略 #

sql
-- 修改保留时间
SELECT remove_retention_policy('sensor_data');

SELECT add_retention_policy(
    'sensor_data',
    INTERVAL '180 days'
);

-- 或使用ALTER JOB
SELECT alter_job(
    job_id,
    schedule_interval => INTERVAL '1 day'
) FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention'
  AND hypertable_name = 'sensor_data';

4.3 删除保留策略 #

sql
-- 删除保留策略
SELECT remove_retention_policy('sensor_data');

-- 验证删除
SELECT * FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention'
  AND hypertable_name = 'sensor_data';

4.4 手动执行保留策略 #

sql
-- 手动执行一次保留策略
SELECT drop_chunks(
    'sensor_data',
    older_than => INTERVAL '90 days'
);

-- 或使用run_job
SELECT run_job(job_id)
FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention'
  AND hypertable_name = 'sensor_data';

五、TRUNCATE删除 #

5.1 基本用法 #

sql
-- 删除所有数据(保留表结构)
TRUNCATE TABLE sensor_data;

-- 级联截断(删除相关表数据)
TRUNCATE TABLE sensor_data CASCADE;

-- 重置序列
TRUNCATE TABLE sensor_data RESTART IDENTITY;

5.2 TRUNCATE特点 #

text
TRUNCATE特点:

优势
├── 速度最快
├── 立即释放空间
├── 不触发触发器
└── 重置序列

限制
├── 不能有外键引用
├── 不能回滚
├── 不返回删除行数
└── 需要TRUNCATE权限

六、删除压缩数据 #

6.1 删除压缩分片 #

sql
-- 查看压缩状态
SELECT 
    chunk_name,
    is_compressed,
    range_start,
    range_end
FROM timescaledb_information.chunks
WHERE hypertable_name = 'sensor_data';

-- drop_chunks可以直接删除压缩分片
SELECT drop_chunks(
    'sensor_data',
    older_than => INTERVAL '90 days'
);

-- 压缩分片会被直接删除,无需解压

6.2 DELETE压缩数据 #

sql
-- 如果必须使用DELETE删除压缩数据
-- 需要先解压

-- 解压分片
SELECT decompress_chunk('_hyper_1_1_chunk');

-- 执行删除
DELETE FROM sensor_data
WHERE time BETWEEN '2024-01-01' AND '2024-01-07'
  AND sensor_id = 1;

-- 重新压缩(如果需要)
SELECT compress_chunk('_hyper_1_1_chunk');

七、删除优化 #

7.1 选择正确的删除方式 #

text
删除方式选择指南:

场景                    推荐方式
─────────────────────────────────────
删除所有数据            TRUNCATE
删除历史数据            drop_chunks
删除特定条件数据        DELETE
自动数据生命周期        保留策略

7.2 DELETE优化 #

sql
-- 使用索引加速DELETE
-- 确保WHERE条件使用索引

-- 查看执行计划
EXPLAIN ANALYZE
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days';

-- 创建合适的索引
CREATE INDEX idx_time ON sensor_data (time);

-- 分批删除大量数据
DO $$
DECLARE
    batch_size INTEGER := 10000;
BEGIN
    LOOP
        DELETE FROM sensor_data
        WHERE time < NOW() - INTERVAL '90 days'
        LIMIT batch_size;
        
        EXIT WHEN NOT FOUND;
        
        COMMIT;
    END LOOP;
END $$;

7.3 VACUUM优化 #

sql
-- DELETE后执行VACUUM
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days';

-- 执行VACUUM释放空间
VACUUM sensor_data;

-- 或执行VACUUM FULL(锁定表)
VACUUM FULL sensor_data;

-- 自动VACUUM
-- PostgreSQL会自动执行VACUUM
-- 可配置自动VACUUM参数
ALTER TABLE sensor_data SET (
    autovacuum_enabled = true,
    autovacuum_vacuum_scale_factor = 0.1
);

八、删除监控 #

8.1 查看删除统计 #

sql
-- 查看表删除统计
SELECT 
    schemaname,
    tablename,
    n_tup_del as deletes,
    n_dead_tup as dead_tuples,
    last_vacuum,
    last_autovacuum
FROM pg_stat_user_tables
WHERE tablename = 'sensor_data';

-- 查看分片删除情况
SELECT 
    hypertable_name,
    count(*) as chunk_count,
    min(range_start) as oldest_data,
    max(range_end) as newest_data
FROM timescaledb_information.chunks
GROUP BY hypertable_name;

8.2 监控保留策略 #

sql
-- 查看保留策略执行历史
SELECT 
    job_id,
    last_run,
    next_run,
    last_run_success,
    total_runs,
    total_failures
FROM timescaledb_information.job_stats
WHERE job_id IN (
    SELECT job_id FROM timescaledb_information.jobs
    WHERE proc_name = 'policy_retention'
);

-- 查看最近删除的分片
SELECT 
    chunk_name,
    range_start,
    range_end,
    is_compressed
FROM timescaledb_information.chunks
WHERE hypertable_name = 'sensor_data'
ORDER BY range_start DESC
LIMIT 10;

九、数据恢复 #

9.1 误删除恢复 #

sql
-- 如果使用了事务,可以回滚
BEGIN;
DELETE FROM sensor_data WHERE ...;
-- 发现误删除
ROLLBACK;

-- 如果已提交,需要从备份恢复
-- 使用pg_restore恢复特定表
pg_restore -d tsdb -t sensor_data backup.dump

-- 或使用时间点恢复(PITR)
-- 需要提前配置WAL归档

9.2 预防措施 #

sql
-- 删除前先查询确认
SELECT count(*) FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days';

-- 使用事务
BEGIN;
DELETE FROM sensor_data WHERE ...;
-- 检查结果
SELECT count(*) FROM sensor_data WHERE ...;
-- 确认无误后提交
COMMIT;
-- 或回滚
ROLLBACK;

-- 使用RETURNING查看删除内容
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days'
RETURNING *;

十、常见问题 #

10.1 删除性能差 #

sql
-- 问题:DELETE性能差
-- 解决:使用drop_chunks

-- 不推荐
DELETE FROM sensor_data
WHERE time < NOW() - INTERVAL '90 days';

-- 推荐
SELECT drop_chunks(
    'sensor_data',
    older_than => INTERVAL '90 days'
);

10.2 磁盘空间未释放 #

sql
-- 问题:DELETE后磁盘空间未释放
-- 解决:执行VACUUM

-- 查看表大小
SELECT pg_size_pretty(pg_total_relation_size('sensor_data'));

-- 执行VACUUM
VACUUM sensor_data;

-- 或VACUUM FULL
VACUUM FULL sensor_data;

10.3 保留策略未执行 #

sql
-- 问题:保留策略未自动执行
-- 解决:检查策略配置

-- 查看策略状态
SELECT * FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention';

-- 手动执行
SELECT run_job(job_id)
FROM timescaledb_information.jobs
WHERE proc_name = 'policy_retention';

-- 检查执行日志
SELECT * FROM timescaledb_information.job_stats
WHERE job_id IN (
    SELECT job_id FROM timescaledb_information.jobs
    WHERE proc_name = 'policy_retention'
);

十一、总结 #

删除操作要点:

操作 适用场景 性能
DELETE 精确删除
drop_chunks 批量删除
TRUNCATE 删除全部 最高
保留策略 自动管理

最佳实践:

  1. 选择正确方式:根据场景选择DELETE或drop_chunks
  2. 使用保留策略:自动管理数据生命周期
  3. 定期VACUUM:DELETE后释放空间
  4. 预防误删:使用事务和RETURNING

下一步,让我们学习连续聚合!

最后更新:2026-03-27