我试图对DELETETRUNCATE命令之间的差异有更深入的了解。我对内部结构的理解大致如下:

DELETE->数据库引擎从相关数据页和输入该行的所有索引页中查找并删除该行。因此,索引越多,删除所需的时间就越长。 br假设以上内容正确(如果不正确,请纠正):


不同的恢复模式如何影响每个语句?如果根本没有效果
删除时,是扫描所有索引还是仅扫描行所在的索引?我假设所有索引都已扫描(而不查找?)
如何复制命令? SQL命令是否在每个订阅服务器上发送和处理?还是MSSQL比这更聪明?


评论

在紧接DROP之前关于TRUNCATE-ing实用程序的问题的答案中,有一些有关DELETE和TRUNCATE的相关信息。您还可以使用此答案中描述的技术自己在日志中进行挖掘,以研究两个命令的效果。

此答案显示了DELETE和TRUNCATE操作的内部。该问题还显示了TRUNCATE更好地工作的特定情况。

@idstam TRUNCATE可以回滚。尼克在回答他所链接的问题时对此进行了介绍。

截断需要“ alter table”权限(在某种意义上,截断是插入式删除操作的替代)。

#1 楼


DELETE->数据库引擎从相关数据页和输入该行的所有索引页中查找并删除该行。因此,索引越多,删除所需的时间越长。 br />

是的,尽管这里有两个选择。可以由执行基本表删除的同一运算符逐行从非聚集索引中删除行。这称为窄(或每行)更新计划:



或者,非聚集索引删除可以由单独的运算符执行,每个非聚集索引一个。在这种情况下(称为广泛的或按索引的更新计划),将完整的操作集存储在工作表(急切后台处理程序)中,然后对每个索引重播一次,通常按特定的非聚集索引键明确地排序以鼓励顺序操作访问模式。




TRUNCATE->只是整体删除表的所有数据页,这是删除内容的更有效选择


是的。 TRUNCATE TABLE的效率更高,其原因有很多:


可能需要更少的锁。截断通常只需要在表级别使用一个模式修改锁(并在每个已释放的扩展区上使用排他锁)。删除可能会获得较低(行或页面)粒度的锁以及任何已释放页面上的排他锁。
只有截断才能保证所有页面都从堆表中释放。即使指定了排他表锁定提示(例如,如果为数据库启用了行版本隔离级别),删除操作也可能在堆中留下空白页。
截断总是保持最少的记录(无论在哪种恢复模式下)采用)。事务日志中仅记录页面重新分配操作。
如果对象的大小为128个范围或更大,则截断可使用延迟丢弃。延迟删除意味着实际的重新分配工作是由后台服务器线程异步执行的。


不同的恢复模式如何影响每个语句?根本没有效果吗?


总是始终记录删除操作(删除的每一行都记录在事务日志中)。如果恢复模型不是FULL,则日志记录的内容会有一些细微的差异,但是从技术上讲,这仍然是完整的日志记录。


删除时,将扫描所有索引或仅扫描那些索引该行在哪里?
我假设所有索引都已扫描(而不查找?)


删除索引中的行(使用显示的窄或宽更新计划之前)始终是通过键(查找)进行的访问。扫描删除的每一行的整个索引的效率极低。让我们再次看一下前面显示的按索引更新计划:



执行计划是需求驱动的管道:父运算符(左侧)驱动子运算符执行通过一次向他们请求一行来工作。 Sort运算符正在阻止(它们必须在产生第一行之前消耗掉全部输入),但是它们仍受其父(索引删除)请求第一行的驱动。索引删除从完成的排序中一次拉出一行,更新每一行的目标非聚集索引。

在广泛的更新计划中,您经常会看到列被列添加到行流中。基本表更新运算符。在这种情况下,“聚集索引删除”会将非聚集索引键列添加到流中。存储引擎需要此数据来找到要从非聚集索引中删除的行:




如何复制命令? SQL命令是否已发送和处理
在每个订户上?还是SQL Server比这更聪明?


不允许使用事务复制或合并复制发布的表上的截断。复制删除内容的方式取决于复制类型及其配置方式。例如,快照复制仅使用批量方法复制表的时间点视图-不会跟踪或应用增量更改。事务复制通过读取日志记录并生成适当的事务以将更改应用于订阅服务器来工作。合并复制使用触发器和元数据表来跟踪更改。

相关阅读:优化更改数据的T-SQL查询