暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

凭什么truncate table它删除数据最快

SmallDB 2026-04-08
0

 

总结

凭什么truncate table它删除数据最快,那么它的实现逻辑是什么样的呢,与我们常用的DELETE有什么区别呢?
核心原因:TRUNCATE DROP 必须超快
表名是逻辑名称(存在系统表)
物理文件是磁盘资源
TRUNCATE 只需要换一个 relfilenode 数字,不需要改名、移动文件

  • • 只做 “逻辑删除”:换 relfilenode、标记旧文件待删
  • • 不做物理 unlink
  • • 物理 unlink 发生在 COMMIT 时,由存储管理器统一批量执行

入口函数

void standard_ProcessUtility(Node* parse_tree, const char* query_string, ParamListInfo params, bool is_top_level,
    DestReceiver* dest,
#ifdef PGXC
    bool sent_to_remote,
#endif /* PGXC */
    char* completion_tag)

{
        case T_TruncateStmt:
#ifdef PGXC
            /*
             * In Postgres-XC, TRUNCATE needs to be launched to remote nodes
             * before AFTER triggers. As this needs an internal control it is
             * managed by this function internally.
             */

            ExecuteTruncate((TruncateStmt*)parse_tree, query_string);
#else
        ExecuteTruncate((TruncateStmt*)parse_tree);
#endif
            break;

        case T_CommentStmt:
            CommentObject((CommentStmt*)parse_tree);
}

src/include/nodes/parsenodes.h

TruncateStmt 完整结构体

/* ----------------------
 *                Truncate Table Statement
 * ----------------------
 */

typedef struct TruncateStmt {
    NodeTag type;              /* 节点类型标记,固定标识这是一个 TRUNCATE 语句节点 */
    List* relations;           /* 要清空的表(可以是多张表) */
    bool restart_seqs;         /* 是否重置表关联的自增序列(SEQUENCE) */
    DropBehavior behavior;     /* 关联约束行为:RESTRICT / CASCADE */
} TruncateStmt;

封装函数-ExecuteTruncate
/*
 * ExecuteTruncate
 *        Executes a TRUNCATE command.
 *
 * This is a multi-relation truncate.  We first open and grab exclusive
 * lock on all relations involved, checking permissions and otherwise
 * verifying that the relation is OK for truncation.  Note that if relations
 * are foreign tables, at this stage, we have not yet checked that their
 * foreign data in external data sources are OK for truncation.  These are
 * checked when foreign data are actually truncated later.  In CASCADE mode,
 * relations having FK references to the targeted relations are automatically
 * added to the group; in RESTRICT mode, we check that all FK references are
 * internal to the group that's being truncated.  Finally all the relations
 * are truncated and reindexed.
 */

void
ExecuteTruncate(TruncateStmt *stmt)
{
    List       *rels = NIL;
    List       *relids = NIL;
    List       *relids_logged = NIL;
    ListCell   *cell;
}

封装函数-ExecuteTruncateGuts
/*
 * ExecuteTruncateGuts
 *
 * Internal implementation of TRUNCATE.  This is called by the actual TRUNCATE
 * command (see above) as well as replication subscribers that execute a
 * replicated TRUNCATE action.
 *
 * explicit_rels is the list of Relations to truncate that the command
 * specified.  relids is the list of Oids corresponding to explicit_rels.
 * relids_logged is the list of Oids (a subset of relids) that require
 * WAL-logging.  This is all a bit redundant, but the existing callers have
 * this information handy in this form.
 */

void
ExecuteTruncateGuts(List *explicit_rels,
                    List *relids,
                    List *relids_logged,
                    DropBehavior behavior, bool restart_seqs,
                    bool run_as_table_owner)

{
    List       *rels;
    List       *seq_relids = NIL;
    HTAB       *ft_htab = NULL;
    EState       *estate;
    
}

新建立一个oid

            RelationSetNewRelfilenumber(rel, rel->rd_rel->relpersistence);

作用:给表换一个全新的空数据文件,把旧文件标记为 “删除”(事务提交后删除),表立刻指向新空文件事务回滚则恢复旧文件,这是类 PG 实现 TRUNCATE 超快的核心原理

实现

新建一个空的 relfilenode 文件,把表的 pg_class.relfilenode 指向新文件

物理删除

            /* Immediate, non-rollbackable truncation is OK */
            heap_truncate_one_rel(rel);

作用:直接清空表的所有数据页,表是本事务刚创建的,不需要考虑回滚
直接物理清空数据,速度极快,这是最直接、最纯粹的删除。

真正的逻辑
CommitTransaction()
  ↓
CallXLogCallbacks()
  ↓
smgrDoPendingDeletes(true);   // true = commit
  ↓
mdunlink()
  ↓
unlink()  // 系统调用,真正删文件

 


文章转载自SmallDB,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论