SQL中的TRUNCATE和DELETE有什么区别


302

TRUNCATEDELETESQL 和有什么不一样?

如果您的答案是特定于平台的,请指出。


4
所有答案都是特定于平台的。标准SQL中没有TRUNCATE命令。因此,它是专有功能,对于每个DBMS供应商而言意味着不同。
nvogel

答案必须是非常特定于实现的,因为正如sqlvogel指出的那样,这是一个非标准命令(TRUNCATE)。要么保留此标记为“ oracle”,要么让它成为社区Wiki风格的答案,并为每个主要RDBMS(Oracle,MS-MSQL,PostgreSQL都实现TRUNCATE ...)添加
后果

如果事务已完成,即表示已提交,则我们不能回滚TRUNCATE命令,但是我们仍然可以从LOG文件回滚DELETE命令,因为DELETE写入会将它们记录在日志文件中,以防将来将来需要从LOG文件回滚。

Answers:


272

这是差异列表。我已经强调了Oracle特定的功能,希望该社区也可以增加其他供应商的特定差异。大多数供应商共有的差异可以直接放在标题的下方,以下突出显示了差异。


总体概述

如果要快速删除表中的所有行,并且确实确定要这样做,并且没有针对表的外键,那么TRUNCATE可能会比DELETE快。

如下所述,必须考虑各种特定于系统的问题。


报表类型

删除是DML,截断是DDL(什么是DDL和DML?


提交和回滚

供应商变量

SQL *服务器

截断可以回滚。

PostgreSQL的

截断可以回滚。

甲骨文

因为TRUNCATE是DDL,所以它涉及两次提交,一次在语句执行之前,一次在语句执行之后。因此,无法回滚截断,并且截断过程中的失败将始终发出提交。

但是,请参阅下面的闪回。


填海工程

删除不恢复空间,截断恢复空间

甲骨文

如果使用REUSE STORAGE子句,则不会取消分配数据段,如果要用表重新加载数据,这可能会稍微提高效率。高水位标记被重置。


行范围

删除可用于删除所有行或仅删除行的子集。截断将删除所有行。

甲骨文

对表进行分区时,可以单独截断各个分区,因此可以部分删除表的所有数据。


对象类型

删除可以应用于集群中的表和表。截断仅适用于表或整个集群。(可能是特定于Oracle的)


数据对象身份

甲骨文

Delete不会影响数据对象ID,但是truncate会分配新的数据对象ID,除非自创建以来从未对该表进行插入,即使回滚单个插入,也会在截断后分配新的数据对象ID 。


闪回(Oracle)

闪回可跨删除执行,但截断可防止闪回至操作之前的状态。

但是,从11gR2版本开始,FLASHBACK ARCHIVE功能允许这样做,但Express Edition中除外

在Oracle中使用FLASHBACK http://docs.oracle.com/cd/E11882_01/appdev.112/e41502/adfns_flashback.htm#ADFNS638


礼遇

变量

甲骨文

可以在表上将Delete授予其他用户或角色,但是如果不使用DROP ANY TABLE授予,则不能进行截断。


重做/撤消

删除会产生少量的重做和大量的撤消。截断每个生成的量可忽略不计。


指标

甲骨文

截断操作使无法使用的索引再次可用。删除没有。


外键

当启用的外键引用表时,无法应用截断。删除的处理取决于外键的配置。


表锁定

甲骨文

截断需要排他表锁,删除需要共享表锁。因此,禁用表锁是一种防止对表进行截断操作的方法。


扳机

DML触发器不会在截断时触发。

甲骨文

DDL触发器可用。


远程执行

甲骨文

截断不能通过数据库链接发出。


身份栏

SQL *服务器

截断将重置IDENTITY列类型的顺序,而删除则不会。


结果集

在大多数实现中,一条DELETE语句可以将删除的行返回给客户端。

例如,在Oracle PL / SQL子程序中,您可以:

DELETE FROM employees_temp
WHERE       employee_id = 299 
RETURNING   first_name,
            last_name
INTO        emp_first_name,
            emp_last_name;

不明白您的第4条陈述:如果我说DELETE [ ] FROM Table;然后*该表中的所有行将被删除,除非FK停止它。顺便说一句,我想这是特定于SQL Server的,您不能在带有FK的表上使用TRUNCATE。
乔·派恩达

其他一些意见:我不同意您的第三条声明,除非它是针对Oracle的。至少对于SQL S.除非您明确要求,否则无论您是DELETE还是TRUNCATE都不会恢复空间(即数据库文件不会在硬盘驱动器上收缩)。
乔·皮内达

1
第五条声明:您可以在sql 2008 r2上回退TRUNCATE TABLE
Eric Labashosky

1
PostgreSQL可以回滚一个TRUNCATE,因此也不会自动提交它。
rfusca 2011年

5
DELETE返回删除的行数,但TRUNCATE不会。这是很愚蠢的观点,但值得一提:)
Deepak Kumar Jha 2015年

190

截断和删除之间的区别如下:

+----------------------------------------+----------------------------------------------+
|                Truncate                |                    Delete                    |
+----------------------------------------+----------------------------------------------+
| We can't Rollback after performing     | We can Rollback after delete.                |
| Truncate.                              |                                              |
|                                        |                                              |
| Example:                               | Example:                                     |
| BEGIN TRAN                             | BEGIN TRAN                                   |
| TRUNCATE TABLE tranTest                | DELETE FROM tranTest                         |
| SELECT * FROM tranTest                 | SELECT * FROM tranTest                       |
| ROLLBACK                               | ROLLBACK                                     |
| SELECT * FROM tranTest                 | SELECT * FROM tranTest                       |
+----------------------------------------+----------------------------------------------+
| Truncate reset identity of table.      | Delete does not reset identity of table.     |
+----------------------------------------+----------------------------------------------+
| It locks the entire table.             | It locks the table row.                      |
+----------------------------------------+----------------------------------------------+
| Its DDL(Data Definition Language)      | Its DML(Data Manipulation Language)          |
| command.                               | command.                                     |
+----------------------------------------+----------------------------------------------+
| We can't use WHERE clause with it.     | We can use WHERE to filter data to delete.   |
+----------------------------------------+----------------------------------------------+
| Trigger is not fired while truncate.   | Trigger is fired.                            |
+----------------------------------------+----------------------------------------------+
| Syntax :                               | Syntax :                                     |
| 1) TRUNCATE TABLE table_name           | 1) DELETE FROM table_name                    |
|                                        | 2) DELETE FROM table_name WHERE              |
|                                        |    example_column_id IN (1,2,3)              |
+----------------------------------------+----------------------------------------------+

截断表的重置标识是什么意思?但是,删除呢?
拉维

1
@jWeaver:这意味着当您将“主键”字段的“身份规范”属性设置为True时,因此,当您向该表中插入数据时,主键列将保留1,2,3,4,5 ...等值(如果Identity开始从1开始,种子为1),并且在截断表时它将丢失所有标识值,因此,当您再次开始向该表中插入数据时,它将从1开始而不是最后一个位置。相反,在DELETE中,即使执行DELETE语句后,它仍保留标识值。抱歉,上图的“删除”列中存在第二个比较点错误。
Bhaumik Patel 2015年

好像您在回答SQL SERVER
Ravi 2015年

4
TRUNCATE和DELETE都可以在SQL SERVER中回滚。并且在第二行中DELETE不会重置身份。现在如何编辑这篇文章?那是在StackOverflow中使用图片的坏事。
Mahmood Jenami '16

2
截断正在回滚!(SQL SERVER)
Aimal Khan

55

下降

DROP命令从数据库中删除表。所有表的行,索引和特权也将被删除。没有DML触发器将被触发。操作无法回滚。

截短

TRUNCATE删除表中的所有行。该操作无法回滚,并且不会触发任何触发器。这样,TRUNCATE更快,并且不使用像DELETE那样的撤消空间。截断时将添加表级别锁。

删除

DELETE命令用于从表中删除行。WHERE子句只能用于删除某些行。如果未指定WHERE条件,则将删除所有行。执行DELETE操作后,您需要COMMIT或ROLLBACK事务以使更改永久或撤消。请注意,此操作将引发表上的所有DELETE触发器。删除时将添加行级别锁。

来自:http : //www.orafaq.com/faq/difference_between_truncate_delete_and_drop_commands


5
对像我这样的初学者的很好的解释
Vikas Kukreti,2015年

短暂而甜蜜
ABH

23

我必须在上面加上所有好的答案:

由于TRUNCATE TABLE是DDL(数据定义语言),而不是DML(数据操作语言)命令,因此Delete Triggers请勿运行。


嗯,触发器...这是个好主意。如果可以的话,我会将其添加到我创建的列表中并归功于Polara。
David Aldridge

SQL Server不允许您使用外键截断表,因此取决于平台,您的级联点可能没有意义。
Meff

PostgreSQL有一个“ TRUNCATE触发器”
a_horse_with_no_name 2012年


17

对于SQL Server或MySQL,如果存在具有自动递增的PK,则truncate将重置计数器。


需要说明的是,如果表具有定义为IDENTITY的列,则适用于SQL Server。删除将保留最后一个自动分配的ID,而“截断”将重置计数器。
Codewerks

由于该问题被标记为ORACLE,因此该答案是错误的,因此被否决了。
盖伊

糟糕,没有看到oracle标签:)
mathieu's

+1 true,并将其重置为0。如果您希望将其改为1DBCC CHECKIDENT (table_name, RESEED, 1)
JohnB 2010年

我已将此添加到社区答案中,并使它在记录特定于供应商的问题时更加友好
David Aldridge

12

“截断不记录任何内容”是正确的。我会更进一步:

截断不在事务的上下文中执行。

截断胜于删除的速度优势应该显而易见。根据您的情况,该优势从微不足道到巨大。

但是,我看到截断无意间会破坏参照完整性,并违反其他约束。通过修改事务外的数据而获得的功能必须与在走钢丝时走钢丝的继承责任相平衡。


7

TRUNCATE是DDL语句,DELETE而是DML语句。以下是两者之间的区别:

  1. TRUNCATEDDL(数据定义语言)语句一样,它不需要提交即可使更改永久生效。这就是为什么无法回滚通过truncate删除的行的原因。另一方面DELETE,DML(数据操作语言)语句因此需要显式提交才能使其效果永久存在。

  2. TRUNCATE总是从表中删除所有行,使表为空且表结构完整,而DELETE如果使用where子句则可能有条件地删除。

  3. TRUNCATE TABLE语句删除的行无法恢复,并且您不能在语句中指定where子句TRUNCATE

  4. TRUNCATE语句不会触发触发器,而不是在DELETE语句上执行删除触发器

是与该主题相关的很好的链接。


6

是的,DELETE较慢,TRUNCATE较快。为什么?

DELETE必须读取记录,检查约束,更新块,更新索引并生成重做/撤消。所有这些都需要时间。

TRUNCATE只需为表(高水位线)和poof调整数据库中的指针!数据不见了。

这是特定于Oracle的AFAIK。


PostgreSQL也与此类似。
加文M.罗伊

6

截短

TRUNCATE SQL查询从表中删除所有行,而不记录单个行的删除。

  • TRUNCATE是DDL命令。
  • TRUNCATE是使用表锁执行的,整个表都被锁定以删除所有记录。
  • 我们不能将WHERE子句与TRUNCATE一起使用。
  • TRUNCATE删除表中的所有行。
  • 最小化事务日志中的日志记录,因此在性能上更快。
  • TRUNCATE TABLE通过取消分配用于存储表数据的数据页面来删除数据,并仅在事务日志中记录页面的解除分配。
  • 要在表上使用Truncate,您至少需要对该表具有ALTER权限。
  • 截断使用的事务空间比Delete语句少。
  • 截断不能与索引视图一起使用。
  • TRUNCATE比DELETE快。

删除

要执行DELETE队列,需要对目标表具有删除权限。如果需要在DELETE中使用WHERE子句,则还需要选择权限。

  • DELETE是DML命令。
  • 使用行锁执行DELETE,表中​​的每一行都被锁定以进行删除。
  • 我们可以使用带DELETE的where子句来过滤和删除特定记录。
  • DELETE命令用于根据WHERE条件从表中删除行。
  • 它维护日志,因此比TRUNCATE慢。
  • DELETE语句一次删除一行,并在事务日志中为每个删除的行记录一个条目。
  • 列保持的标识DELETE保留该标识。
  • 要使用删除,您需要在表上具有DELETE权限。
  • 删除使用比Truncate语句更多的事务空间。
  • 删除可用于索引视图。

5

如果不小心您使用Delete / Truncate从表中删除了所有数据。您可以回滚已提交的事务。恢复最后一次备份并运行事务日志,直到即将发生“删除/截断”为止。

以下相关信息来自博客文章

在处理数据库时,我们正在使用Delete和Truncate而不知道它们之间的区别。在本文中,我们将讨论Sql中Delete和Truncate之间的区别。

删除:

  • 删除是DML命令。
  • 使用行锁执行Delete语句,表中的每一行都被锁定以进行删除。
  • 我们可以在where子句中指定过滤器。
  • 如果存在条件,它将删除指定的数据。
  • 删除活动是触发器,因为操作是单独记录的。
  • 比截断慢,因为它保留日志

截短

  • 截断是DDL命令。
  • 截断表始终锁定表和页面,但不锁定每一行,因为它会删除所有数据。
  • 无法使用Where条件。
  • 它删除所有数据。
  • 截断表无法激活触发器,因为该操作不会记录单个行的删除。
  • 在性能上更快,因为它不保留任何日志。

注意:与事务一起使用时,删除和截断都可以回滚。如果事务已完成,意味着已提交,则我们无法回滚Truncate命令,但仍可以从日志文件回滚Delete命令,因为delete写入会将它们记录在日志文件中,以防万一将来需要从日志文件中回滚。

如果您有一个外键约束引用您要截断的表,则即使引用表中没有数据,该约束也将不起作用。这是因为外键检查是使用DDL而不是DML完成的。可以通过临时禁用表的外键约束来解决此问题。

删除表是已记录的操作。因此,删除每一行都会记录在事务日志中,这使其变慢。截断表还会删除表中的所有行,但不会记录每行的删除,而是会记录表的数据页的取消分配,从而使其更快。

〜如果不小心使用删除/截断从表中删除了所有数据。您可以回滚已提交的事务。还原最后一个备份并运行事务日志,直到即将发生“删除/截断”为止。


1
感谢@Lucas:他内联了内容。我只是将其放在大括号中,以表明它来自其他来源。
AstroCB 2014年

4

我相信在SQL Server 2005中,您可以回滚截断


4

删除

DELETE命令用于从表中删除行。WHERE子句只能用于删除某些行。如果未指定WHERE条件,则将删除所有行。执行DELETE操作后,您需要COMMIT或ROLLBACK事务以使更改永久或撤消。请注意,此操作将引发表上的所有DELETE触发器。

截短

TRUNCATE删除表中的所有行。该操作无法回滚,并且不会触发任何触发器。因此,TRUCATE速度更快,并且使用的撤消空间不如DELETE那样多。

下降

DROP命令从数据库中删除表。所有表的行,索引和特权也将被删除。没有DML触发器将被触发。操作无法回滚。


DROP和TRUNCATE是DDL命令,而DELETE是DML命令。因此,DELETE操作可以回滚(撤消),而DROP和TRUNCATE操作不能回滚。

来自:http : //www.orafaq.com/faq/difference_between_truncate_delete_and_drop_commands


这会给当前答案增加些什么吗?
David Aldridge

3

如果包装在事务中,则TRUNCATE可以回滚。

请查看下面的两个参考并进行自我测试:

http://blog.sqlauthority.com/2007/12/26/sql-server-truncate-cant-be-rolled-back-using-log-files-after-transaction-session-is-closed/

http://sqlblog.com/blogs/kalen_delaney/archive/2010/10/12/tsql-tuesday-11-rolling-back-truncate-table.aspx

TRUNCATE与DELETE是SQL采访中的一个臭名昭著的问题之一。只要确保您正确地向面试官解释一下,否则可能会使您付出工作的代价。问题是,没有多少人意识到这一点,因此如果您告诉他们可以回滚YES Truncate,他们很可能会认为答案是错误的。


2

对原始答案进行较小的修正-删除也会产生大量的重做(因为撤消本身受重做保护)。这可以从自动跟踪输出中看到:

SQL> delete from t1;

10918 rows deleted.

Elapsed: 00:00:00.58

Execution Plan
----------------------------------------------------------
   0      DELETE STATEMENT Optimizer=FIRST_ROWS (Cost=43 Card=1)
   1    0   DELETE OF 'T1'
   2    1     TABLE ACCESS (FULL) OF 'T1' (TABLE) (Cost=43 Card=1)




Statistics
----------------------------------------------------------
         30  recursive calls
      12118  db block gets
        213  consistent gets
        142  physical reads
    3975328  redo size
        441  bytes sent via SQL*Net to client
        537  bytes received via SQL*Net from client
          4  SQL*Net roundtrips to/from client
          2  sorts (memory)
          0  sorts (disk)
      10918  rows processed

它的旧线程,但据我了解,截断只会生成大量的重做日志,而当delete会生成撤消和重做。
Saurabh Sinha

2

这是我关于SQL Server中DELETE和TRUNCATE之间的区别的详细答案

删除数据 :首先,两者都可用于从表中删除行。
但是,DELETE不仅可以用于从表中删除行,还可以用于从视图中删除行,也可以根据提供者的能力来删除OPENROWSET或OPENQUERY的结果。

FROM子句:使用DELETE,您还可以使用另一个FROM子句,根据另一个表中的行从一个表/视图/行集功能限制中删除行。在该FROM子句中,您还可以编写普通的JOIN条件。实际上,您可以通过将SELECT替换为DELETE并删除列名,从不包含任何聚合函数的SELECT语句中创建DELETE语句。
使用TRUNCATE,您将无法做到这一点。

WHERE:TRUNCATE不能具有WHERE条件,但DELETE可以。这意味着使用TRUNCATE不能删除特定的行或特定的行组。TRUNCATE TABLE与没有WHERE子句的DELETE语句相似。

表现:TRUNCATE TABLE更快,并且使用更少的系统和事务日志资源。原因之一是两个语句使用的锁。使用行锁执行DELETE语句,表中的每一行都被锁定以删除。TRUNCATE TABLE始终锁定表和页面,但不锁定每一行。

事务日志:DELETE语句一次删除一行,并在事务日志中为每一行单独输入。
TRUNCATE TABLE通过取消分配用于存储表数据的数据页面来删除数据,并仅在事务日志中记录页面的解除分配。

页面:执行DELETE语句后,表仍可以包含空页面。TRUNCATE通过取消分配用于存储表数据的数据页来删除数据。

触发器:TRUNCATE不会激活表上的删除触发器。因此,在使用TRUNCATE时必须非常小心。如果在表上定义了删除触发器,则永远不要使用TRUNCATE来在删除行时执行一些自动清理或日志记录操作。

标识列:如果表包含一个标识列,则使用TRUNCATE,该列的计数器将重置为该列定义的种子值。如果未定义种子,则使用默认值1。DELETE不会重置身份计数器。因此,如果要保留身份计数器,请使用DELETE。

复制:DELETE可用于事务复制或合并复制中使用的表。
虽然TRUNCATE不能用于事务复制或合并复制中涉及的表。

回滚:可以回退 DELETE语句。
如果TRUNCATE包含在TRANSACTION块中并且未关闭会话,则也可以回滚。会话关闭后,您将无法回滚TRUNCATE。

限制:如果DELETE语句违反触发器或试图删除具有FOREIGN KEY约束的另一个表中的数据所引用的行,则DELETE语句可能会失败。如果DELETE删除了多行,并且任何删除的行都违反了触发器或约束,则该语句将被取消,将返回错误,并且不会删除任何行。
而且,如果对视图使用DELETE,则该视图必须是可更新的视图。无法对索引视图中使用的表使用TRUNCATE。
不能对FOREIGN KEY约束所引用的表使用TRUNCATE,除非具有引用自己的外键的表。


嗨,Mangal-感谢您的回答,特别是对于SQL * Server特定的问题。您是否认为可以将这些观点与已接受的社区Wiki答案整合在一起?
大卫·奥尔德里奇

是的,但是如何以及在哪里?对不起,我是新来的。
Mangal Pardeshi 2015年

“因此,如果您想保留身份计数器,请使用DELETE”DECLARE @ai as bigint SET @ai =IDENT_CURRENT('tablename') TRUNCATE TABLE tablename DBCC checkident('tablename', RESEED, @ai)
mpag

1

最大的区别是截断是非记录操作,而删除是。

简而言之,这意味着在数据库崩溃的情况下,您无法恢复通过truncate操作的数据,而使用delete可以恢复。

在这里更多细节


1

DELETE语句:此命令根据where子句中给出的条件仅从表中删除行,或者,如果未指定任何条件,则从表中删除所有行。但是它不会释放包含表的空间。

SQL DELETE语句的语法为:

从table_name删除[WHERE条件];

TRUNCATE语句:此命令用于删除表中的所有行并释放包含表的空间。


1

删除

DELETE is a DML command
DELETE you can rollback
Delete = Only Delete- so it can be rolled back
In DELETE you can write conditions using WHERE clause
Syntax  Delete from [Table] where [Condition]

截短

TRUNCATE is a DDL command
You can't rollback in TRUNCATE, TRUNCATE removes the record permanently
Truncate = Delete+Commit -so we can't roll back
You can't use conditions(WHERE clause) in TRUNCATE
Syntax  Truncate table [Table]

有关更多详细信息,请访问

http://www.zilckh.com/what-is-the-difference-between-truncate-and-delete/


1

这两个操作的另一个区别是,如果表包含一个标识列,则在TRUNCATE下将该列的计数器重置为1(或重置为该列定义的种子值)。删除不具有此影响。


0

简而言之,截断不会记录任何内容(因此速度更快,但无法撤消),而删除则被记录(并且可以是较大事务的一部分,将回滚等)。如果在dev的表中有不需要的数据,通常最好进行截断,因为这样就不会冒填充事务日志的风险


0

方便的一个重要原因是,当您需要刷新数百万行表中的数据,但又不想重建它时。“删除*”将永远保留,而Truncate的性能影响则可以忽略不计。


0

无法通过dblink执行DDL。


0

我会在matthieu的帖子中发表评论,但我没有代表...

在MySQL中,自动递增计数器会使用truncate重置,但不会使用delete重置。


0

不是truncate不会在SQL Server中记录任何内容。truncate不会记录任何信息,但会记录在其上触发了TRUNCATE的表的数据页的重新分配。

如果我们在开始时定义了事务,则截断的记录可以回滚,并且回滚后可以恢复截断的记录。但是在提交被截断的事务之后,无法从事务日志备份中恢复截断的记录。



0

SQL中的Truncate和Delete是两个命令,用于从表中删除或删除数据。尽管这两个Sql命令本质上都非常基础,但是在您使用它之前,除非您熟悉细节,否则它们都会造成很多麻烦。如果需要删除太多数据并且日志段不够用,那么错误选择命令可能会导致处理过程非常缓慢,甚至毁坏日志段。这就是为什么知道何时在SQL中使用截断和删除命令至关重要的原因,但是在使用这些命令之前,您应该了解截断和删除之间的区别,并基于它们,我们应该能够确定何时使用DELETE是删除的更好选择应该使用data或TRUNCATE来清除表。

请参考检查点击这里


0

通过发出TRUNCATE TABLE语句,您正在指示SQL Server删除表中的每个记录,而不进行任何日志记录或事务处理。


0

DELETE语句可以具有WHERE子句以删除特定的记录,而TRUNCATE语句不需要任何内容​​并擦除整个表。重要的是,DELETE语句记录删除的日期,而TRUNCATE语句不记录。


0

特定于Microsoft sql Server的另一不同之处在于delete您可以使用output语句来跟踪已删除的记录,例如:

delete from [SomeTable]
output deleted.Id, deleted.Name

您无法使用来执行此操作truncate

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.