SQL中的TRUNCATE和DELETE有什么区别

时间:2020-03-06 14:47:06  来源:igfitidea点击:

为了回答关于DROPTRUNCATE之间的区别的问题,我错误地写下了这个问题的答案,但是我认为不分享是一种耻辱,因此我将针对自己的问题发表自己的答案。 ..甚至合乎道德吗? :)

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

解决方案

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

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

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

删除是DML,截断是DDL

由供应商可变

SQL *服务器

截断可以回滚。

PostgreSQL的

截断可以回滚。

甲骨文

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

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

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

甲骨文

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

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

甲骨文

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

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

甲骨文

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

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

但是,从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;

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

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

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

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

此处有更多详细信息

"截断不记录任何内容"是正确的。我会走得更远:

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

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

但是,我看到截断会无意间中断引用完整性,并违反其他约束。通过修改事务外部的数据而获得的功能必须与在走钢丝的情况下继承绳索时要承担的责任进行权衡。

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

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

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

无法通过dblink执行DDL。

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

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

TRUNCATE快,DELETE慢。

虽然,TRUNCATE没有责任。

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

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

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

这是特定于Oracle的AFAIK。

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

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

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

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

  • 由于TRUNCATE是DDL(数据定义语言)语句,因此不需要提交即可使更改永久生效。这就是为什么无法回滚通过truncate删除的行的原因。另一方面," DELETE"是DML(数据操作语言)语句,因此需要显式提交才能使其效果永久存在。
  • TRUNCATE总是删除表中的所有行,使表为空并且表结构保持完整,而如果使用where子句,DELETE可能有条件地删除。
  • TRUNCATE TABLE语句删除的行无法恢复,并且我们不能在TRUNCATE语句中指定where子句。
  • TRUNCATE语句不会触发触发器,而不是DELETE语句上的删除触发器

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