• SQL Server索引进阶第十一篇:索引碎片分析与解决(上)


     

    索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就获取到的,很多的技术人员因为不恰当的创建索引,最后使得其效果适得其反,可以说“成也索引,败也索引”。

     

     

     

    本系列文章来自Stairway to SQL Server Indexes,然后经过我们团队的理解和整理发布在agilesharp,希望对广大的技术朋友在如何使用索引上有所帮助。

     

    系列文章索目录:

    SQL Server索引进阶第一篇:索引介绍
    SQL Server索引进阶第二篇:深入非聚集索引
    SQL Server索引进阶第三篇:聚集索引
    SQL Server索引进阶第四篇:页和区

     

    SQL Server索引进阶第五篇:索引包含列
    SQL Server索引进阶第六篇:书签
    SQL Server索引进阶第七篇:过滤的索引

     

    SQL Server索引进阶第八篇:唯一索引
    SQL Server索引进阶第九篇:解读执行计划
    SQL Server索引进阶第十篇:索引的内部结构
    SQL Server索引进阶第十一篇:索引碎片分析与解决(上)
    SQL Server索引进阶第十一篇:索引碎片分析与解决(中)-碎片发生原理深度剖析
    SQL Server索引进阶第十二篇:索引的创建,修改和删除
    SQL Server索引进阶第十三篇:Insert,Update,Delete语句
    SQL Server索引进阶第十四篇:索引统计
    SQL Server索引进阶第十五篇:索引的最佳实践

     



    相关有关索引碎片的问题,大家应该是听过不少,也许也很多的朋友已经做了与之相关的工作。那我们今天就来看看这个问题。

    为了更好的说明这个问题,我们首先来普及一些背景知识。


    知识普及

     

    我们都知道,数据库中的每一个表要么是堆表,要么就是包含聚集索引的表,或者我们称之为有序表。如果表是一个堆表,那么在使用非聚集索引查询数据的时候,会使用书签查找去底层的数据表中去检索需要的数据,这个书签查找会通过每一个索引中包含的行标识(RID)去定位每一个底层数据表的数据行。如果表上面有聚集索引,那么在使用非聚集索引查找其他需要数据的时候,就会使用聚集索引键去定位底层的数据行。

     

    我们也知道,索引是由索引页组成的,索引中的每一个条目包含在页中。每8个页组成一个块。

     

    索引的层级是从底向上的,就是一个树结构,最下面的就是第0层,也是叶节点。索引中的根节点处于整个索引的最上层。

     

    如果要扫描整个索引,那么就意味着必须要读取页节点中的每一个页(要么是数据页,要么是索引页)。其中,每个页都包含着一个指向它前面的页和一个指向它后面也的指针。之前,我们也提过:如果单看某一层节点,其实就是一个双向链表。还是上个图,大家感受一下。


     

    我们应该知道:页(不管是数据页,还是索引页 ,还是其他的类型的页)处于的逻辑顺序和它的物理顺便不一定就是一样的,也就说,在A页中的指针指向了它的下一个页B,也就说A和B页在逻辑上面是一起的,但是它们在物理上面可能不一样,甚至B页和A页在物理上相隔几百个页。

     

    如果在逻辑上面相连的页在物理存储级别相隔的越近,那么在读取这些页的时候所花的I/O成本也就越小,因为产生磁盘的磁头移动带来的延迟。相反,如果他们的物理存储顺序和逻辑顺序一致,那么SQL Server在读取的时候,就可以一次读取,因为每次会读取一个块(8个页)。

    好了,普及知识之后,我们就来看看什么是碎片。


    什么是索引碎片

     

    索引碎片可以分为两类:内部索引碎片和外部索引碎片。下面我们就来具体的看看而这之前的区别以及如何检查。

     

    内部索引碎片

     

    每一个索引页中都包含一些索引的条目(就类似数据页包含很多的数据行一行),这一点我们在之前讲过了的。但是,很多的时候,不是每个页都包含了最大的条数。例如,一个页的大小8k,也就是4096字节,除去一些页头,页脚等,还剩下8000多字节,如果每个索引条目的大小事100字节,那么这个索引页最大就可以包含80个条目,但是很多的情况下,却没有包含这么多。

     

    也就说,很多的时候,索引页并没有完全的填满,或者这是问题,或许这么我们特意这样的,我们后续会提到。当我们谈到索引碎片的时候,我们往往就是指这些索引页没有完全填满。或者说的更加明白一点就是:我们原本是希望页都被填满的,但是随着数据的增删改,使得索引中的数据没有填满,结果如下:


     

     

    图不是很清晰,大家意会一下就行了。

     

    我们可以使用
    sys.dm_db_index_physical_stats来查看相关的内部碎片的情况,执行查询如下:

    1. SELECT IX.name AS 'Name'
    2. , PS.index_level AS 'Level'
    3. , PS.page_count AS 'Pages'
    4. , PS.avg_page_space_used_in_percent AS 'Page Fullness (%)'
    5. FROM sys.dm_db_index_physical_stats(
    6. DB_ID(),
    7. OBJECT_ID('Sales.SalesOrderDetail'),
    8. DEFAULT, DEFAULT, 'DETAILED') PS
    9. JOIN sys.indexes IX
    10. ON IX.OBJECT_ID = PS.OBJECT_ID AND IX.index_id = PS.index_id
    复制代码

     

     

    执行结果如图:



    我们可以看到每个索引的页面的填充情况。

    下面,我们再来讲讲外部索引碎片。

     

    外部索引碎片

     

    理解了上面的问题,这个外部索引碎片就好理解了,最简单的说法就是:索引中的索引页的逻辑顺序和物理顺序不一致。我们通过个图对比的来看看。



    在上图中,一个索引包含了16个页。但是这16页不是包含在2个相连的块中的,而是分布在不同的地方,因为它们之前中的一些块被其他的对象占用了。这样就导致了16个页在物理上面不连续,这就是碎片。在读取的时候,就会消耗额外的I/O。

     

    和之前一样,我们可以使用
    sys.dm_db_index_physical_stats来查看外部碎片的情况。但是这里的参数值可能要发生变化了:之前在sys.dm_db_index_physical_stats最后一个参数值是'DETAILED',这里我们的值是LIMITED或者Default。因为外部碎片关注的是索引页之前的连续性问题,不关注每一个页中的数据,此时只是部分的扫描,没有必要全部的扫描。大家可以参看MSDN的去进一步的理解这些参数的含义。

     

    查询如下:

    1. SELECT IX.name AS 'Name'
    2. , PS.index_level AS 'Level'
    3. , PS.page_count AS 'Pages'
    4. , PS.avg_fragmentation_in_percent AS 'External Fragmentation (%)'
    5. , PS.fragment_count AS 'Fragments'
    6. , PS.avg_fragment_size_in_pages AS 'Avg Fragment Size'
    7. FROM sys.dm_db_index_physical_stats(
    8. DB_ID(),
    9. OBJECT_ID('Sales.SalesOrderDetail'),
    10. DEFAULT, DEFAULT, 'LIMITED') PS
    11. JOIN sys.indexes IX
    12. ON IX.OBJECT_ID = PS.OBJECT_ID AND IX.index_id = PS.index_id
    复制代码

     

     

    结果如下:



    除了使用脚本之外,我们还可以在SQL Server管理器中查看,在某个索引上面右键,属性,如下:


    好,我们下一篇文章就来进一步的谈谈一下的内容:

    是什么导致了碎片

    如何解决碎片问题

    后文更加精彩!!!

  • 相关阅读:
    黑马程序员系列第十篇 异常
    黑马程序员系列第八篇 IO(2)
    黑马程序员系列第九篇 类加载器
    黑马程序员系列第六篇 面向对象基础
    黑马程序员系列第七篇 IO(1)
    黑马程序员系列第五篇 集合(2)
    黑马程序员系列第四篇 集合(1)
    黑马程序员系列第三篇 反射
    vue 自定义指令集合
    计算图片缩放比例 使图片不变形
  • 原文地址:https://www.cnblogs.com/lteal/p/2799328.html
Copyright © 2020-2023  润新知