总结
凭什么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进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




