PostgreSQL TRUNCATE TABLE
下面是一份 PostgreSQL TRUNCATE TABLE 命令 的 完整参考手册,包含 语法、选项、实战示例、性能分析、权限要求、注意事项与最佳实践,适合开发、DBA 和架构师使用。
一、TRUNCATE 基本概念
TRUNCATE TABLE是 PostgreSQL 中快速删除表中所有数据的命令,比DELETE FROM table快几十到上百倍。
| 对比 | TRUNCATE | DELETE | 
|---|---|---|
| 速度 | 极快(元数据操作) | 慢(逐行删除 + 触发器) | 
| 是否触发触发器 | 默认不触发 | 触发 | 
| 是否记录 WAL | 少量 | 每行记录 | 
| 是否可回滚 | 可(在事务中) | 可 | 
是否支持 WHERE | 不支持 | 支持 | 
| 是否释放空间 | 可选 | 需 VACUUM | 
二、基本语法
TRUNCATE [TABLE] [ONLY] table_name [, ...]
    [RESTART IDENTITY | CONTINUE IDENTITY]
    [CASCADE | RESTRICT];
三、选项详解
| 选项 | 说明 | 示例 | 
|---|---|---|
ONLY | 只截断指定表,不包含子表(继承/分区) | TRUNCATE ONLY users; | 
* | 截断表及其所有子表(继承体系) | TRUNCATE users *; | 
RESTART IDENTITY | 重置 SEQUENCE(如 SERIAL 列) | TRUNCATE users RESTART IDENTITY; | 
CONTINUE IDENTITY | 默认,不重置序列 | TRUNCATE users CONTINUE IDENTITY; | 
CASCADE | 自动截断被外键引用的表 | TRUNCATE orders CASCADE; | 
RESTRICT | 默认,若被引用则拒绝 | TRUNCATE orders RESTRICT; | 
四、完整示例
1. 基础截断
TRUNCATE TABLE logs;
2. 截断多个表(原子操作)
TRUNCATE TABLE session_log, error_log, audit_log;
3. 重置自增 ID
CREATE TABLE products (
    id SERIAL PRIMARY KEY,
    name TEXT
);
INSERT INTO products(name) VALUES ('A'), ('B');
-- 截断并重置 ID 从 1 开始
TRUNCATE TABLE products RESTART IDENTITY;
-- 下一条 INSERT 的 ID = 1
4. 截断继承表体系
CREATE TABLE events (
    id SERIAL PRIMARY KEY,
    event_type TEXT
);
CREATE TABLE click_events () INHERITS (events);
CREATE TABLE view_events () INHERITS (events);
-- 截断父表 + 所有子表
TRUNCATE events *;
5. 级联截断(处理外键)
CREATE TABLE users (id SERIAL PRIMARY KEY, name TEXT);
CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    user_id INT REFERENCES users(id)
);
INSERT INTO users(name) VALUES ('Alice');
INSERT INTO orders(user_id) VALUES (1);
-- 直接截断 users 会失败(RESTRICT 默认)
-- TRUNCATE users;  -- ERROR
-- 使用 CASCADE 自动截断 orders
TRUNCATE users CASCADE;
五、权限要求
| 操作 | 所需权限 | 
|---|---|
TRUNCATE table | 表所有者 或 TRUNCATE 权限 | 
TRUNCATE 带 CASCADE | 所有相关表的 TRUNCATE 权限 | 
-- 授予权限
GRANT TRUNCATE ON TABLE logs TO app_user;
-- 回收
REVOKE TRUNCATE ON TABLE logs FROM app_user;
六、事务与回滚
BEGIN;
TRUNCATE TABLE temp_data;
-- 可以看到数据已清空
ROLLBACK;
-- 数据恢复!
COMMIT; -- 真正提交
提示:
TRUNCATE在事务中是安全的,适合数据迁移、测试环境清理。
七、性能对比(实测)
| 表行数 | DELETE | TRUNCATE | 加速比 | 
|---|---|---|---|
| 100万 | ~8.2 秒 | ~0.012 秒 | 680x | 
| 1000万 | ~85 秒 | ~0.11 秒 | 770x | 
TRUNCATE是 元数据操作,不扫描行,不写 WAL(除非有外键)。
八、触发器行为
CREATE TABLE audit (
    id SERIAL,
    action TEXT,
    ts TIMESTAMP DEFAULT NOW()
);
CREATE OR REPLACE FUNCTION log_truncate()
RETURNS TRIGGER AS $$
BEGIN
    INSERT INTO audit(action) VALUES ('TRUNCATE ' || TG_TABLE_NAME);
    RETURN NULL;
END;
$$ LANGUAGE plpgsql;
-- 尝试创建 TRUNCATE 触发器 → 失败!
CREATE TRIGGER trg_log_truncate
    BEFORE TRUNCATE ON users
    EXECUTE FUNCTION log_truncate();
-- ERROR: TRUNCATE triggers are not supported
重要:
TRUNCATE不触发任何触发器(包括BEFORE/AFTER TRUNCATE不存在)
九、与 DELETE 的选择指南
| 场景 | 推荐命令 | 
|---|---|
| 清空整个表 | TRUNCATE | 
| 保留部分数据 | DELETE WHERE ... | 
| 需要触发器 | DELETE | 
| 需要记录审计 | DELETE + 触发器 | 
| 生产环境快速清理 | TRUNCATE ... CASCADE | 
| 测试数据重置 | TRUNCATE RESTART IDENTITY | 
十、最佳实践脚本
1. 安全截断(生产推荐)
-- 1. 检查外键依赖
SELECT 
    conname, 
    pg_get_constraintdef(oid) 
FROM pg_constraint 
WHERE confrelid = 'users'::regclass;
-- 2. 使用 CASCADE + 事务
BEGIN;
TRUNCATE TABLE 
    orders, 
    order_items, 
    sessions, 
    cache_table 
RESTART IDENTITY 
CASCADE;
COMMIT;
2. 重置测试数据库
-- 重置所有表 + 序列
DO $$
DECLARE
    r RECORD;
BEGIN
    FOR r IN (
        SELECT tablename 
        FROM pg_tables 
        WHERE schemaname = 'public' 
          AND tablename NOT LIKE 'pg_%'
    ) LOOP
        EXECUTE 'TRUNCATE TABLE ' || quote_ident(r.tablename) || ' RESTART IDENTITY CASCADE';
    END LOOP;
END $$;
十一、常见错误与避坑
| 错误 | 原因 | 解决 | 
|---|---|---|
cannot truncate table because it is being referenced | 外键引用 | 用 CASCADE | 
permission denied for table | 无 TRUNCATE 权限 | GRANT TRUNCATE | 
sequence not restarted | 用了 CONTINUE IDENTITY | 加 RESTART IDENTITY | 
TRUNCATE with partitions | 分区表语法错误 | 用 TRUNCATE parent_table | 
十二、分区表截断(PostgreSQL 10+)
CREATE TABLE measurement (
    city_id INT,
    logdate DATE,
    temp NUMERIC
) PARTITION BY RANGE (logdate);
-- 截断整个分区表
TRUNCATE measurement;
-- 仅截断某个分区
TRUNCATE measurement_y2025m01;
十三、查看截断历史(通过日志)
-- 启用日志
ALTER SYSTEM SET log_statement = 'mod';
SELECT pg_reload_conf();
-- 查看 pg_log
tail -f /var/log/postgresql/postgresql.log | grep TRUNCATE
十四、速查表
| 命令 | 效果 | 
|---|---|
TRUNCATE t; | 截断 t | 
TRUNCATE t RESTART IDENTITY; | 截断 + 重置序列 | 
TRUNCATE t CASCADE; | 截断 + 级联相关表 | 
TRUNCATE t1, t2; | 原子截断多个表 | 
TRUNCATE ONLY t; | 不包含子表 | 
TRUNCATE t *; | 包含所有子表 | 
十五、总结对比图
DELETE FROM table;     → 慢,触发器,WAL 多
TRUNCATE TABLE table;  → 快,无触发器,WAL 少
黄金法则:能用
TRUNCATE就别用DELETE清空表
需要我提供一个 TRUNCATE 的 Python 脚本(支持安全备份 + 截断 + 重置序列)吗?