删除与截断

Stu*_*ler 36 sql-server database-internals

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

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

TRUNCATE -> 简单地删除所有表的数据页,使其成为删除表内容的更有效选项。

假设以上是正确的(如果不正确,请纠正我):

  1. 不同的恢复模式如何影响每个语句?如果有任何影响
  2. 删除时,是扫描所有索引还是仅扫描行所在的索引?我假设所有索引都被扫描(而不是搜索?)
  3. 命令是如何复制的?是否在每个订阅者上发送和处理 SQL 命令?还是 MSSQL 比这更智能一点?

Pau*_*ite 60

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

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

每行删除

或者,非聚集索引删除可以由单独的操作员执行,每个非聚集索引一个。在这种情况下(称为广泛或每索引更新计划),完整的操作集存储在工作表(eager spool)中,然后每个索引重放一次,通常按特定非聚集索引的键显式排序以鼓励顺序访问模式。

每个索引删除

TRUNCATE -> 简单地删除所有表的数据页,使其成为删除表内容的更有效选项。

是的。 TRUNCATE TABLE由于多种原因,效率更高:

  1. 可能需要更少的锁。截断通常仅需要在表级(和排它锁在每个单个架构修改锁程度解除分配)。删除可能会以较低的(行或页)粒度获取锁以及释放任何上的排他锁。
  2. 只有截断才能保证从堆表中释放所有页面。即使指定了排他表锁提示(例如,如果为数据库启用了行版本隔离级别),删除操作也可能会在堆中留下空页。
  3. 截断总是最少记录(不管使用的恢复模型如何)。事务日志中只记录页面解除分配操作。
  4. 如果对象大小为 128 或更大,截断可以使用延迟删除。延迟删除意味着实际的释放工作是由后台服务器线程异步执行的。

不同的恢复模式如何影响每个语句?有什么影响吗?

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

删除时,是扫描所有索引还是仅扫描行所在的索引?我假设所有索引都被扫描(而不是搜索?)

删除索引中的一行(使用前面显示的窄更新计划或宽更新计划)始终是键访问(搜索)。为删除的每一行扫描整个索引将是非常低效的。让我们再看一下之前显示的每个索引更新计划:

宽计划2

执行计划是需求驱动的管道:父操作符(左侧)通过一次向子操作符请求一行来驱动子操作符执行工作。Sort 运算符是阻塞的(它们必须在生成第一个已排序的行之前使用它们的全部输入),但它们仍然由请求第一行的父级(索引删除)驱动。索引删除一次从完成的排序中拉出一行,更新每一行的目标非聚集索引。

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

输出列表详细信息

命令是如何复制的?是否在每个订阅者上发送和处理 SQL 命令?或者 SQL Server 是否比这更智能?

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

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