重建并重新索引所有内容后,为什么我的数据库仍然碎片化?


41

我有一个数据库,我试图通过运行以下T-SQL对所有表进行碎片整理:

SELECT 
        'ALTER INDEX all ON ' + name + ' REORGANIZE;' + CHAR(10) +
        'ALTER INDEX all ON ' + name + ' REBUILD;'
    FROM sys.tables

然后将输出复制并粘贴到新的查询窗口中并运行它。我没有任何错误,但是仍然有碎片。我也尝试单独运行两个命令,但仍然有碎片。注意:REORGANIZE Aaron 已使我意识到这是不必要的,并且我知道可以使用动态sql来自动执行此操作。

我运行此命令以确定我仍然有碎片:

SELECT * FROM 
sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL , NULL, NULL) 
WHERE avg_fragmentation_in_percent > 0

我得到:

database_id object_id   index_id    partition_number    index_type_desc alloc_unit_type_desc    index_depth index_level avg_fragmentation_in_percent    fragment_count  avg_fragment_size_in_pages  page_count  avg_page_space_used_in_percent  record_count    ghost_record_count  version_ghost_record_count  min_record_size_in_bytes    max_record_size_in_bytes    avg_record_size_in_bytes    forwarded_record_count  compressed_page_count
85  171147655   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   36.3636363636364    5   2.2 11  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  421576540   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   75  7   1.14285714285714    8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  965578478   1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   14.7058823529412    6   5.66666666666667    34  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1061578820  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   40  4   1.25    5   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1109578991  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   30.7692307692308    5   2.6 13  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1205579333  2   1   NONCLUSTERED INDEX  IN_ROW_DATA 2   0   50  5   1.6 8   NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL
85  1493580359  1   1   CLUSTERED INDEX IN_ROW_DATA 2   0   50  6   1.66666666666667    10  NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL    NULL

我知道我缺少真正的基本知识,但我不知道。


您遇到什么错误?另外,您是否有理由重组和重建同一件事?
肖恩·梅尔顿

肖恩,对我遗漏一个字表示歉意。我没有错。至于为什么我要运行两个命令,我分别尝试了每个命令之后就做了。我更新了我的问题。
贾斯汀·迪林(Dusting)

Answers:


38

桌子很小。表中的页数为:

11,8,6,5,13,8,10

它们总共占用480kb。实际上没有什么要整理的。

编辑:这值得更多的解释。

通常会从混合范围(而不是统一范围)中分配新表或索引的前8页。因此,可以从不同的混合扩展区分配前8页中的每一个。因此,消耗8页的表或索引可能具有8个片段,在8个不同的混合范围中的每一个上都有1个。

因此,使用更广泛的碎片整理脚本(下面链接了几个示例)倾向于排除小表。IIRC,其中一页或全部少于500页。在这些大小下,进行碎片整理几乎没有好处,并且碎片化数据可能会因混合扩展区分配而产生偏差。


好的,除非其他人有更好的答案,否则这是令人满意的,我会将您的答案标记为正确。
贾斯汀·迪林Dearing'Sep

3
+1同意马克。实际有一些数据时,请担心碎片。:-)
亚伦·贝特朗

我完全理解你在说什么。只是出于好奇,这是因为db引擎无法对这么几个页面进行碎片整理吗?我的意思是,这一定有原因。
Thomas Stringer

3
不是因为它不能,而是为什么要打扰?这样做对I / O几乎没有影响-尤其是因为几乎可以保证将如此小的表存储在内存中。
亚伦·伯特兰

1
只是。似乎很奇怪,仅此而已。假设我正在编写一个用于检查和报告索引碎片的应用程序,那么我将不得不添加附加逻辑以不仅测试碎片百分比,而且还要测试页面数量,以免出现虚假警报。
Thomas Stringer

19

引自“ Microsoft SQL Server 2000索引碎片整理最佳实践 ”:

“碎片会影响磁盘I / O。因此,请关注较大的索引,因为它们的页面不太可能被SQL Server缓存。请使用DBCC SHOWCONTIG报告的页数来了解索引的大小(每个页面都是大小为8 KB)。通常,您不必担心少于1,000页的索引的碎片级别。在测试中,包含10,000页以上的索引实现了性能提升,而在页数明显更多的索引上获得的收益最大(更大)超过50,000页)。”

因此,这种回答会回答您的问题,并支持Mark和Aaron的回答。

您可以在以下来自Brent Ozar的文章中找到有关索引碎片的良好信息:

也可以在Kimberly Tripp的博客上找到有关索引的大量信息(也涉及碎片问题)。


12

这并不是要回答您的问题,但是永远不会在评论中显示。您可以动态构建此脚本,而不必将输出复制并粘贴到另一个窗口中。考虑到绝对没有理由REORGANIZEREBUILD

DECLARE @sql NVARCHAR(MAX) = N'';

SELECT @sql += N'ALTER INDEX all ON ' + name + ' REBUILD;
    ' FROM sys.tables;

PRINT @sql; -- to see the first 8,000 characters and make sure it checks out
-- EXEC sp_executesql @sql;

亚伦,感谢您指出动态sql,我对动态sql非常清楚,在解决方案生效之前,我不会将其自动化。其他阅读本文的人可能应该知道。
贾斯汀·迪林
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.