66

有人可以快速概述一下使用以下两个语句的利弊:

TRUNCATE TABLE dbo.MyTable

对比

DELETE FROM dbo.MyTable

似乎他们都在做同样的事情。但两者之间一定有区别。

4

11 回答 11

93

TRUNCATE不会生成任何回滚数据,这使其闪电般快速。它只是释放表使用的数据页。

但是,如果您在事务中并希望能够“撤消”此删除,则需要使用DELETE FROM,它提供了回滚的能力。

编辑: 请注意,以上对于 SQL Server 是不正确的(但它确实适用于 Oracle)。在 SQL Server 中,如果您在事务中并且该事务尚未提交,则可以回滚截断操作。从 SQL Server 的角度来看,DELETE FROM 和 TRUNCATE 之间的一个关键区别是:“DELETE 语句一次删除一行,并在事务日志中为每个删除的行记录一个条目。TRUNCATE TABLE 通过释放数据页来删除数据用于存储表数据并仅在事务日志中记录页面释放。”

换句话说,在 TRUNCATE 期间的日志记录较少,因为只有页面释放记录在事务日志中,而 DELETE FROM 记录了每行删除。这就是 TRUNCATE 快如闪电的原因之一。

另请注意,从该 MSDN 链接中,您不能截断由外键约束引用、参与索引视图或使用事务复制或合并复制发布的表。

编辑 2: 另一个关键点是 TRUNCATE TABLE 会将您的身份重置为初始种子,而 DELETE FROM 将从中断处继续递增。参考:本·罗宾逊的回答。

于 2010-07-15T14:02:27.493 回答
48

其他答案中未提及的另一个关键点是TRUNCATE TABLE将您的身份重置为初始种子,而将从中断处继续递增。DELETE FROM

于 2010-07-15T14:12:40.770 回答
9

从安全角度来看,另一个区别是 TRUNCATE 需要对表有 ALTER 权限,而 DELETE 只需要对那个表有(鼓)DELETE 权限。

于 2013-07-03T15:35:44.583 回答
4

TRUNCATE TABLE不记录交易。这意味着它对于大桌子来说是闪电般的快。缺点是您无法撤消操作。

DELETE FROM在事务日志中记录正在删除的每一行,因此该操作需要一段时间并导致您的事务日志急剧增长。好处是您可以在需要时撤消操作。

于 2010-07-15T14:07:48.410 回答
3

SQL Server 中删除与截断的概述

在此连接后获取完整文章:SQL Server 中的删除与截断

在此处输入图像描述

/*Truncate - Syntax*/
TRUNCATE TABLE table_name

/*Delete - Syntax*/
DELETE FROM table_name
WHERE some_condition
于 2017-09-07T10:08:54.403 回答
2

我相信只有在显式事务中执行操作时才能回滚删除和截断。否则,您将不得不执行还原以恢复已删除的数据

于 2013-04-24T15:44:33.493 回答
1

根本区别在于它们的记录方式。DELETE 和 TRUNCATE 的记录方式不同,但两者都可以以完全相同的方式回滚。记录所有更改数据的操作。在 SQL Server 中,没有非日志操作之类的东西。

于 2011-06-29T11:28:10.103 回答
0

DELETEvs之间的另一个区别TRUNCATE是表损坏时的行为。

例如:

DELETE FROM table_name;

最终会出现错误:

消息 3314,第 21 级,状态 3,第 1 行

在撤消数据库“...”中记录的操作期间,日志记录 ID () 处发生错误。通常,特定故障以前会作为错误记录在 Windows 事件日志服务中。从备份中恢复数据库或文件,或修复数据库。

消息 0,级别 20,状态 0,行 0

当前命令发生严重错误。结果,如果有的话,应该丢弃。

虽然TRUNCATE会工作:

TRUNCATE TABLE table_name;
-- Command(s) completed successfully.
于 2017-08-10T16:50:11.073 回答
0

非常重要的一件事(imo)并且在其他答案中没有提到是TRUNCATE需要模式稳定性锁Sch-S,而DELETE使用行锁。让我们检查以下内容:

BEGIN TRANSACTION;

BEGIN TRY
    -- Truncate below will take LCK_M_SCH_S lock for TABLE_A
    TRUNCATE TABLE TABLE_A

    -- Lets say the query below takes 5 hours to execute
    INSERT INTO
        TABLE_A
    SELECT
        *
    FROM
        GIANT_TABLE (NOLOCK)
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRANSACTION;
    THROW
END CATCH

IF @@TRANCOUNT > 0
    COMMIT TRANSACTION;

现在假设在此查询开始 1-2 分钟后,假设我们尝试执行以下操作:

SELECT COUNT(*) FROM TABLE_A (NOLOCK)

请注意,我使用了NOLOCK子句。你认为现在会发生什么?此查询将等待 5 小时。为什么?因为NOLOCK子句需要Sch-S锁定,TABLE_A但该TRUNCATE子句已经锁定Sch-S。由于我们还没有提交事务,即使在该TRUNCATE子句之后,锁仍然处于打开状态。Sch-S锁定表基本上意味着要么TABLE_A通过添加/删除列等进行更改,要么被截断。您甚至无法执行以下操作:

SELECT object_id('TABLE_A')

这也会卡住5个小时。但是,如果将其替换TRUNCATEDELETE FROM,您将看到Sch-S表上没有锁定,并且上面的查询也不会卡住。

于 2017-05-26T07:28:30.463 回答
0

加上所有的答案,另一点要考虑的是Truncate不会触delete trigger发表的,但delete语句会delete trigger为每一行触发表的。

于 2018-08-11T10:43:21.010 回答
-2

truncate 不做任何记录,delete 做,所以如果你有很多记录,你的 trans log 是巨大的

于 2010-07-15T14:02:43.950 回答