索引监控数据分析

通过上一节收集的数据组合在一起,并经过分析阶段,制定出对索引的创建、删除、修改方案,然后在实施阶段进行部署

主要关注下面几个部分:

1.审查服务器状态

2.未使用索引

3.索引计划使用

一:审查服务器状态

1.性能计数器

2.等待信息

3.Buffer分配

Use IndexDemo
WITH CounterSummary
AS (
  SELECT create_date
    ,server_name
    ,MAX(CASE WHEN counter_name = 'Forwarded Records/sec'
      THEN Calculated_Counter_value END) ForwardedRecords
    ,MAX(CASE WHEN counter_name = 'Forwarded Records/sec'
      THEN Calculated_Counter_value END)
      / (NULLIF(MAX(CASE WHEN counter_name = 'Batch Requests/sec'
      THEN Calculated_Counter_value END),0) * 10) AS ForwardedRecordRatio
  FROM dbo.IndexingCounters
  WHERE counter_name IN ('Forwarded Records/sec','Batch Requests/sec')			
  GROUP BY create_date
    ,server_name
)
SELECT server_name
  ,MIN(ForwardedRecords) AS MinForwardedRecords
  ,AVG(ForwardedRecords) AS AvgForwardedRecords
  ,MAX(ForwardedRecords) AS MaxForwardedRecords
  ,MIN(ForwardedRecordRatio) AS MinForwardedRecordRatio
  ,AVG(ForwardedRecordRatio) AS AvgForwardedRecordRatio
  ,MAX(ForwardedRecordRatio) AS MaxForwardedRecordRatio
  ,100.*SUM(CASE WHEN ForwardedRecordRatio > 1 THEN 1 END)
    /COUNT(*) AS PctViolation
FROM CounterSummary
GROUP BY server_name

 创建一个堆表,插入数据,并更新其中一些数据,引发堆分页,最后执行上面的查询检查情况

USE IndexDemo
GO
IF OBJECT_ID('HeapExample', 'U') IS NOT NULL
    DROP TABLE HeapExample
CREATE TABLE dbo.HeapExample
    (
      ID INT IDENTITY ,
      FillerData VARCHAR(2000)
    )
INSERT  INTO dbo.HeapExample
        ( FillerData
        )
        SELECT  REPLICATE('X', 100)
        FROM    sys.all_objects
UPDATE  dbo.HeapExample
SET     FillerData = REPLICATE('X', 2000)
WHERE   ID % 5 = 1
GO
SELECT  *
FROM    dbo.HeapExample
WHERE   ID % 3 = 1

 当Forwarded Records发生,再次执行代码

如果存在Forward Records问题,通常有3种解决方案

1.更改数据类型,把变长改成定长,如varchar-char,不够这种情况可能不是很通用,而且可能伴随数据截断等问题

2.改变表的存储结构,也就是创建一个聚集索引在上面,从而移除堆表的组织数据机制

3.就是重建堆表

ALTER TABLE dbo.HeapExample REBUILD

 2.Access Methods\FreeSpace Scans/sec(关于堆表的另一个计数器)

当在堆表中插入数据时,他会标识发生了什么操作,在插入过程中,可能会引起GAM、SGAM和PFS页的改动。如果插入的频率足够高,可能会在这些页上产生争用

通过汇总最小值、平均值和最大值来进行分析

WITH    CounterSummary
          AS ( SELECT   create_date ,
                        server_name ,
                        MAX(CASE WHEN counter_name = 'FreeSpace Scans/sec'
                                 THEN Calculated_Counter_value
                            END) FreeSpaceScans ,
                        MAX(CASE WHEN counter_name = 'FreeSpace Scans/sec'
                                 THEN Calculated_Counter_value
                            END)
                        / ( NULLIF(MAX(CASE WHEN counter_name = 'Batch Requests/sec'
                                            THEN Calculated_Counter_value
                                       END), 0) * 10 ) AS ForwardedRecordRatio
               FROM     dbo.IndexingCounters
               WHERE    counter_name IN ( 'FreeSpace Scans/sec',
                                          'Batch Requests/sec' )
               GROUP BY create_date ,
                        server_name
             )
    SELECT  server_name ,
            MIN(FreeSpaceScans) AS MinFreeSpaceScans ,
            AVG(FreeSpaceScans) AS AvgFreeSpaceScans ,
            MAX(FreeSpaceScans) AS MaxFreeSpaceScans ,
            MIN(ForwardedRecordRatio) AS MinForwardedRecordRatio ,
            AVG(ForwardedRecordRatio) AS AvgForwardedRecordRatio ,
            MAX(ForwardedRecordRatio) AS MaxForwardedRecordRatio ,
            100. * SUM(CASE WHEN ForwardedRecordRatio > 1 THEN 1
                       END) / COUNT(*) AS PctViolation
    FROM    CounterSummary
    GROUP BY server_name

如果FreeSpace Scans/sec很高,应该集中分析哪个堆有最高的插入数率。可以使用:sys.dm_db_index_operational_stats来查找

SELECT  QUOTENAME(DB_NAME(database_id)) AS database_name ,
        QUOTENAME(OBJECT_SCHEMA_NAME(object_id, database_id)) + '.'
        + QUOTENAME(OBJECT_NAME(object_id, database_id)) AS ObjectName ,
        SUM(leaf_insert_count) AS leaf_insert_count ,
        SUM(leaf_allocation_count) AS leaf_allocation_count
FROM    dbo.index_operational_stats_history
WHERE   index_id = 0
        AND database_id > 4
GROUP BY object_id ,
        database_id
ORDER BY leaf_insert_count DESC

 在查找到根源之后,最好的方法就是加上聚集索引,改变其数据组织机制

3.Access Methods\Full Scans/sec,通过这个计数器可查看Full Scans/sec的值,这个值包含聚集、非聚集索引及堆表。高值意味着查询存在性能问题,这种情况可能会引起Page Life Expectancy(用于衡量内存压力的一个主要计数器)的变动,这将加大数据在内存中的存储时间,并引起I/O问题

下面的脚本用于分析当前Full Scans/sec的值,同样也需要考虑Batch Requests/sec 计数器,如果这两个值的比例超过1000,就需要引起注意

WITH    CounterSummary
          AS ( SELECT   create_date ,
                        server_name ,
                        MAX(CASE WHEN counter_name = 'Full Scans/sec'
                                 THEN Calculated_Counter_value
                            END) FullScans ,
                        MAX(CASE WHEN counter_name = 'Full Scans/sec'
                                 THEN Calculated_Counter_value
                            END)
                        / ( NULLIF(MAX(CASE WHEN counter_name = 'Batch Requests/sec'
                                            THEN Calculated_Counter_value
                                       END), 0) * 1000 ) AS FullRatio
               FROM     dbo.IndexingCounters
               WHERE    counter_name IN ( 'Full Scans/sec',
                                          'Batch Requests/sec' )
               GROUP BY create_date ,
                        server_name
             )
    SELECT  server_name ,
            MIN(FullScans) AS MinFullScans ,
            AVG(FullScans) AS AvgFullScans ,
            MAX(FullScans) AS MaxFullScans ,
            MIN(FullRatio) AS MinFullRatio ,
            AVG(FullRatio) AS AvgFullRatio ,
            MAX(FullRatio) AS MaxFullRatio ,
            100. * SUM(CASE WHEN FullRatio > 1 THEN 1
                            ELSE 0
                       END) / COUNT(*) AS PctViolation
    FROM    CounterSummary
    GROUP BY server_name

 4. Access Methods\Index Searches/sec,大部分情况下,索引查找会比索引扫描有效,这个计数器显示SQL Server 实例上发生索引查找的比率,这个值相对于Full Scans/sec来说越高越好。这个比率是衡量索引是否有效的标准之一,这两个值的比率一般是1000:1

WITH    CounterSummary
          AS ( SELECT   create_date ,
                        server_name ,
                        MAX(CASE WHEN counter_name = 'Index Searches/sec'
                                 THEN Calculated_Counter_value
                            END) IndexSearches ,
                        MAX(CASE WHEN counter_name = 'Index Searches/sec'
                                 THEN Calculated_Counter_value
                            END)
                        / ( NULLIF(MAX(CASE WHEN counter_name = 'Full Scans/sec'
                                            THEN Calculated_Counter_value
                                       END), 0) * 1000 ) AS SearchToScanRatio
               FROM     dbo.IndexingCounters
               WHERE    counter_name IN ( 'Index Searches/sec',
                                          'Full Scans/sec' )
               GROUP BY create_date ,
                        server_name
             )
    SELECT  server_name ,
            MIN(IndexSearches) AS MinIndexSearches ,
            AVG(IndexSearches) AS AvgIndexSearches ,
            MAX(IndexSearches) AS MaxIndexSearches ,
            MIN(SearchToScanRatio) AS MinSearchToScanRatio ,
            AVG(SearchToScanRatio) AS AvgSearchToScanRatio ,
            MAX(SearchToScanRatio) AS MaxSearchToScanRatio ,
            100. * SUM(CASE WHEN SearchToScanRatio > 1 THEN 1
                       END) / COUNT(*) AS PctViolation
    FROM    CounterSummary
    GROUP BY server_name

猜你喜欢

转载自www.cnblogs.com/sunliyuan/p/9033221.html
今日推荐