为什么删除行时非聚集索引使用更多空间?


22

我有一张有75亿行和5个索引的大表。当我删除大约1000万行时,我注意到非聚集索引似乎增加了它们存储在页面上的数量。

我写了一个查询dm_db_partition_stats来报告页面中的差异(之后-之前):

dm_db_partition_stats增量

索引1是聚集索引,索引2是主键。其他的则是非集群且非唯一的。

为什么这些非聚集索引上的页面增加?
我希望最坏的数字保持不变。
我确实看到性能计数器报告了删除期间页面拆分的增加。

删除时,幻像记录是否必须移至另一页?这和“唯一符”有关吗?

我们正处于推出RCSI的中间阶段,但是现在,RCSI已关闭。

它是可用性组中的主要节点。我知道快照以某种方式在次要上使用。如果这很有意义,我会感到惊讶。我计划对此进行深入研究(查看dbcc页面输出)以了解更多信息。希望有人看到过类似的内容。


只是一个问题-对增长的一个索引执行REORGANIZE,会发生什么?删除了几页?如果您在删除前重新组织,会发生什么?我主要是在考虑内部机制在某些情况下可能会更容易分配整个新页面并合并,但不会清理空页面。我知道REORGANIZE最终会丢弃大量页面,即使是在相对完整但相对较大的索引上也是如此。
Laughing Vergil

好问题@LaughingVergil当我得到答案时,我会回到这里报告。(但是可能需要一段时间)。
Michael J Swart

在我们的情况下,这种增加只是暂时现象。有了足够的耐心,Ghost清理最终完成了工作,并且索引的大小减小了。
Michael J Swart

Answers:


28

一种可能使我非常开心的情况:

  • 这些行最初是在数据库未启用读取提交的快照(RCSI),快照隔离(SI)或可用性组(AG)时写入的
  • 启用了RCSI或SI,或已将数据库添加到可用性组中
  • 删除期间,已删除行中添加了14字节的时间戳以支持RCSI / SI / AG读取

由于此服务器是AG中的主要服务器,因此它与次要服务器一样受到影响。版本信息添加在主要数据库上-数据页面在主要数据库和次要数据库上完全相同。当AG正在更新行时,辅助服务器利用版本存储进行读取,但是辅助服务器不会将自己的时间戳版本写入页面。他们只是从主要工作继承了版本。

为了说明增长,我进行了Stack Overflow数据库导出(未启用RCSI)并在Posts表上创建了一堆索引。我使用sp_BlitzIndex @Mode = 2检查了索引大小(将副本复制/粘贴到电子表格中,并进行了一些清理以最大化信息密度):

sp_BlitzIndex之前

然后,我删除了大约一半的行:

BEGIN TRAN;
DELETE dbo.Posts WHERE Id % 2 = 0;
GO

有趣的是,在进行删除的同时,数据文件也在增长以适应时间戳!“ SSMS磁盘使用情况报告”显示了增长事件-这只是说明的顶部:

成长事件

(必须喜欢一个演示,其中的删除操作使数据库得以扩展。)在运行删除操作时,我再次运行了sp_BlitzIndex。请注意,聚集索引的行较少,但是其大小已经增加了约1.5GB。AcceptedAnswerId上的非聚集索引已急剧增长-它们是基于一个很小的值(通常为null)的索引,因此它们的索引大小几乎增加了一倍!

删除过程中的sp_BlitzIndex

我不必等待删除操作完成就可以证明这一点,因此我将在那里停止演示。重点是:在对启用RCSI,SI或AG之前实现的表进行大的删除时,索引(包括集群的)实际上可以增加以适应版本存储时间戳的增加。


3
这就是解释。事实证明,还有其他情况可能导致缺少14个版本字节。在我的测试中,似乎离线重建索引将重建没有版本字节的行。
Michael J Swart
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.