【问题标题】:Stored procedure - truncate table存储过程 - 截断表
【发布时间】:2025-12-15 04:30:01
【问题描述】:

我创建了一个存储过程来将数据添加到表中。在模拟方式中,步骤是:

  • 截断原始表
  • 选择数据到原始表中

将数据选择到原始表中的查询很长(可能需要将近一分钟才能完成),这意味着该表超过一分钟是空的。

为了修复这个空表,我将存储过程更改为:

  • 将数据选择到#temp 表中
  • 截断原始表
  • 将 * 从 #temp 插入原始文件

当存储过程运行时,我在原始表上做了一个select *,它是空的(刷新,在存储过程完成之前它一直是空的)。

无论它在代码中的实际位置,截断是否发生在过程的开头?如果是这样,我还能做些什么来控制何时删除数据?

【问题讨论】:

  • #tmp 中有多少条记录?
  • SQL 语句是按顺序执行的,所以截断发生在插入临时表完成之后。
  • @Saeed 表中有 77,000 条记录。
  • sp 被 HTTP Get 中的代码调用,所以我不希望表在刷新期间为空超过一分钟。当我问这个问题时,我正在使用从表中选择 * 进行测试,但刚才我通过在邮递员中点击端点进行了测试,但我从未收到空响应。因此,似乎将截断稍后放在 sp 中确实有效。

标签: sql-server tsql stored-procedures


【解决方案1】:

一个非常有趣的方法将数据快速移动到一个表中是使用分区切换。

使用myStaging2 中的新数据创建两个临时表myStaging1myStaging2。它们必须在 same 数据库和 same 文件组中(所以不是临时表或表变量),the EXACT same columns, PKs, FKs and indexes.

然后运行这个:

SET XACT_ABORT, NOCOUNT ON;      -- force immediate rollback if session is killed

BEGIN TRAN;

ALTER TABLE myTargetTable SWITCH TO myStaging1
WITH ( WAIT_AT_LOW_PRIORITY ( MAX_DURATION = 1 MINUTES, ABORT_AFTER_WAIT = BLOCKERS ));
-- not strictly necessary to use WAIT_AT_LOW_PRIORITY but better for blocking
-- use SELF instead of BLOCKERS to kill your own session

ALTER TABLE myStaging2 SWITCH TO myTargetTable
WITH (WAIT_AT_LOW_PRIORITY (MAX_DURATION = 0 MINUTES, ABORT_AFTER_WAIT = BLOCKERS));
-- force blockers off immediately

COMMIT TRAN;

TRUNCATE TABLE myStaging1;

这非常快,因为它只是元数据更改。

您会问:分区仅在 Enterprise Edition(或 Developer)上受支持,这有什么帮助?

仍然允许在彼此之间切换非分区表即使在标准版或快捷版中也是如此。

有关此技术的更多信息,请参阅 this article by Kendra Little

【讨论】:

  • 这改变了生活!
  • 虽然这可能非常有用,但它并不能回答或解决问题。
  • @RedDogsRock 为什么这对你没有帮助?
【解决方案2】:

sp 由 HTTP Get 中的代码调用,因此我不希望表在刷新期间为空超过一分钟。当我问这个问题时,我正在使用从表中选择 * 进行测试,但刚才我通过点击邮递员中的端点进行了测试,但我从未收到空响应。因此,似乎将截断稍后放在 sp 中确实有效。

【讨论】: