【问题标题】:Pros & Cons of TRUNCATE vs DELETE FROMTRUNCATE 与 DELETE FROM 的优缺点
【发布时间】:2011-03-16 10:27:22
【问题描述】:

有人可以快速概述一下使用以下两种语句的优缺点吗:

TRUNCATE TABLE dbo.MyTable

DELETE FROM dbo.MyTable

说到底,他们似乎都在做同样的事情;但是两者之间一定有区别吗。

【问题讨论】:

    标签: sql-server sql-server-2008 tsql sql-delete truncate


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    【解决方案2】:

    其他答案中未提及的另一个关键点是TRUNCATE TABLE重置您的身份到初始种子,而DELETE FROM 将从哪里开始递增它停止了。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

        • TRUNCATE 已记录,可以像 DELETE 一样撤消 - 通过使用 ROLLBACK 或 RESTORE。
        • 只有在使用事务的情况下,如果提交了截断,就不能回滚。它是 DDL,没有记录到日志文件中。
        • 有趣的是,这个回复和标记为答案的回复几乎都说了同样的话,但是这个回复被拒绝为 -1,而标记为回复的回复被投票给 +7(至少在我正在写这篇文章的那一刻)。正如@dcp 之前提到的,this 是一篇很好的文章,描述了 TRUNCATE 与 DELETE 的回滚行为。
        【解决方案5】:

        SQL Server 中删除与截断的概述

        在此连接后获取完整文章:Delete Vs Truncate in SQL Server

        /*Truncate - Syntax*/
        TRUNCATE TABLE table_name
        
        /*Delete - Syntax*/
        DELETE FROM table_name
        WHERE some_condition
        

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              【解决方案8】:

              有一点非常重要(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 个小时。但是,如果您将 TRUNCATE 替换为 DELETE FROM,您将看到表上将没有 Sch-S 锁定,并且上述查询不会卡住。

              【讨论】:

                【解决方案9】:

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

                例如:

                DELETE FROM table_name;
                

                会报错:

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

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

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

                当前命令发生严重错误。结果(如果有)应丢弃。

                虽然TRUNCATE 可以工作:

                TRUNCATE TABLE table_name;
                -- Command(s) completed successfully.
                

                【讨论】:

                  【解决方案10】:

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

                  【讨论】:

                    【解决方案11】:

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

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2011-01-26
                      • 2017-04-29
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2014-10-07
                      • 2011-11-03
                      相关资源
                      最近更新 更多