[英]Reduce SQL Server table fragmentation without adding/dropping a clustered index?
我有一个大型数据库(90GB数据,70GB索引)在过去一年中一直在缓慢增长,并且增长/变化不仅造成了索引的大量内部碎片,而且导致了表本身的大量内部碎片。
很容易解决(大量)非常分散的索引 - REORGANIZE或REBUILD将根据它们的碎片程度来处理它 - 但我在清理实际表碎片时可以找到的唯一建议是添加聚簇索引到桌子。 之后我会立即删除它,因为我不希望桌面上有聚簇索引,但是有没有另一种方法可以在没有聚簇索引的情况下执行此操作? 一个“DBCC”命令会这样做吗?
谢谢你的帮助。
让我们清楚一点,因为这是一个常见问题,对于每个使用SQL Server的公司来说都是一个严重的问题。
这个问题以及对CREATE CLUSTERED INDEX的需求被误解了。
同意拥有一个永久的聚集索引比没有一个更好。 但这不是重点,无论如何它都将导致长时间的讨论,所以让我们把它放在一边,专注于发布的问题。
关键是,你在堆上有大量的碎片。 你一直称它为“表”,但物理数据存储或DataStructure级别没有这样的东西。 表是逻辑概念,而不是物理概念。 它是物理DataStructures的集合。 该系列是两种可能性之一:
堆
加上所有非聚集指数
加上文字/图像链
或聚集指数
(消除堆和一个非聚集索引)
加上所有非聚集指数
加上文字/图像链。
堆得严重分散; 插入/删除/更新越多,插入/删除/更新越多,碎片就越多。
没有办法按原样清理堆。 MS不提供设施(其他供应商也提供)。
但是,我们知道Create Clustered Index完全重写和重新排序堆。 因此,该方法(不是技巧)是仅为了对Heap进行去碎片而创建Clustered Index,然后将其删除。 你需要table_size x 1.25的db中的可用空间。
无论如何,使用FILLFACTOR可以减少未来的碎片。 然后,Heap将占用更多的分配空间,允许将来由于更新而插入,删除和行扩展。
请注意,有三个碎片级别 ; 这只涉及III级,堆内的碎片,这是由于缺乏聚集指数造成的
作为一项单独的任务,在其他时候,您可能希望考虑实现永久性聚集索引,这完全消除了碎片......但这与已发布的问题是分开的。
SqlRyan:
虽然这不能为我的问题提供神奇的解决方案,但很明显我的问题是SQL Server限制的结果,添加聚簇索引是对堆进行“碎片整理”的唯一方法。
不完全的。 我不会称之为“限制”。
我为消除堆中的碎片而给出的方法是创建聚簇索引, 然后删除它。 IE浏览器。 暂时,唯一的目的是纠正碎片。
在表上永久地实现聚簇索引是一个更好的解决方案,因为它减少了整体碎片(DataStructure仍然可以获得碎片,在下面的链接中引用详细信息),这远远小于堆中发生的碎片。
Relational数据库中的每个表(“管道”或“队列”表除外)都应具有聚簇索引,以便利用其各种优势。
聚集索引应该在分发数据的列上(避免INSERT冲突),永远不要在单调增加的列上编制索引,例如记录ID 1 ,它保证最后一页中的INSERT热点。
1.每个文件上的记录ID使您的“数据库”成为非关系记录文件系统,仅为方便起见使用SQL。 此类文件没有完整性,功能或速度关系数据库。
安德鲁希尔:
你能否进一步评论“请注意,有三个级别的碎片;这只涉及III级” - 其他两个级别的碎片是什么?
在MS SQL和Sybase ASE中,有三个碎片级别 ,并且在每个级别中,有几个不同的类型 。 请记住,在处理Fragmentation时,我们必须关注DataStructures,而不是关注表(表是DataStructures的集合,如上所述)。 级别是:
一级•额外数据结构
有关DataStructure之外,数据库之内或之内。
二级•数据结构
在相关的DataStructure中,上面的页面(跨所有页面)
这是DBA最常处理的级别。
三级•页面
在相关的DataStructure中,在Pages内
这些链接提供了完整的细节碎片。 它们特定于Sybase ASE,但在结构级别,该信息适用于MS SQL。
请注意,我给出的方法是Level II,它纠正了II级和III级碎片。
您声明您添加了聚簇索引以缓解表碎片,然后立即将其删除。
聚簇索引通过对群集密钥进行排序来删除碎片,但您说该密钥将来无法使用。 这引出了一个问题:为什么要使用这个密钥进行碎片整理?
创建这个集群密钥并保留它是有意义的,因为你显然希望/需要以这种方式排序的数据。 您说数据更改会导致数据移动处罚无法承担; 您是否考虑过使用比默认值更低的FILLFACTOR
创建索引? 根据数据变化模式,您可以从低至80%的收益中受益。 然后,每页有20%的“未使用”空间,但是当更改聚簇键值时,页面拆分较少的好处。
这可以帮到你吗?
没有人在谈论的问题是硬盘驱动器上的数据或日志设备文件的碎片! 每个人都在讨论索引的碎片化以及如何避免/限制碎片。
仅供参考:创建数据库时,您可以指定.MDF的INITIAL大小以及需要增长时的增长量。 您对.LDF文件执行相同操作。 没有任何保证,当这两个文件增加时,为所需的额外磁盘空间分配的磁盘空间将与所分配的现有磁盘空间在物理上一致!
每当这两个设备文件中的一个需要扩展时,硬盘驱动器磁盘空间就有可能碎片化。 这意味着硬盘驱动器上的磁头需要更加努力(并花费更多时间)从硬盘驱动器的一个部分移动到另一个部分以访问数据库中的必要数据。 这类似于购买一小块土地并建造一个适合该土地的房屋。 当你需要扩建房屋时,除非你购买隔壁的空地,否则你没有更多土地可供使用 - 除非 - 如果其他人在此期间已经购买了这块土地并在其上建造房屋怎么办? 然后你不能扩大你的房子。 唯一的可能性是在“邻里”购买另一块土地并在其上建造另一栋房屋。 问题变成了 - 你和你的两个孩子将住在A楼,你的妻子和第三个孩子将住在B楼。这将是一种痛苦(只要你还在结婚)。
解决这种情况的解决方案是“购买更大的土地,拿起现有的房屋(即数据库),将其移至更大的土地,然后在那里扩建房屋”。 那么 - 你如何用数据库做到这一点? 执行完整备份,删除数据库(除非您有足够的可用磁盘空间来保留旧的碎片数据库 - 以防万一)以及新数据库),创建一个分配了大量初始磁盘空间的全新数据库(不保证操作系统将确保您请求的空间是连续的)然后将数据库还原到刚创建的新数据库空间。 是的 - 这很痛苦,但我不知道任何可用于SQL数据库文件的“自动磁盘碎片整理程序”软件。
您可以通过使用NOTRUNCATE运行DBCC SHRINKFILE来压缩堆。
根据评论,我发现你没有使用一个渗透聚集索引进行测试。
为了正确看待这一点,我们拥有每天1000万个新行的数据库,所有表都有聚簇索引。 删除的“间隙”将通过预定的ALTER INDEX(以及前向指针/页面拆分)删除。
索引后你的12GB表可能是2GB:它只分配了12GB,但也是大量碎片。
我理解您受到传统设计设计约束的痛苦。
您是否有机会在另一台服务器上恢复相关表的备份并创建聚簇索引? 如果在一组窄的唯一列或标识列上创建聚簇索引,则很可能会减少总表(数据和索引)的大小。
在我的一个遗留应用程序中,所有数据都是通过视图访问的。 我能够修改基础表的模式,添加标识列和聚簇索引,而不会影响应用程序。
拥有堆的另一个缺点是与任何已转发的行相关联的额外IO。
当我被问到是否有任何证据证明我们需要永久保留在桌面上的clusted索引时,我发现下面的文章是有效的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.