• 有关索引的DMV(转)


    转自:http://www.cnblogs.com/CareySon/archive/2012/05/17/2505981.html

    1.查看那些被大量更新,却很少被使用的索引

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT                                                    
        DB_NAME() AS DatabaseName 
        , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , s.user_updates 
        , s.system_seeks + s.system_scans + s.system_lookups 
                              AS [System usage] 
    INTO #TempUnusedIndexes 
    FROM   sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
        AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE 1=2 
    EXEC sp_MSForEachDB 'USE [?];                           
    INSERT INTO #TempUnusedIndexes 
    SELECT TOP 20 
        DB_NAME() AS DatabaseName 
        , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , s.user_updates 
        , s.system_seeks + s.system_scans + s.system_lookups 
                                             AS [System usage] 
    FROM   sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
        AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE s.database_id = DB_ID() 
    AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0 
    AND s.user_seeks = 0 
        AND s.user_scans = 0 
        AND s.user_lookups = 0 
    AND i.name IS NOT NULL 
    ORDER BY s.user_updates DESC'                            
    SELECT TOP 20 * FROM #TempUnusedIndexes ORDER BY [user_updates] DESC 
    DROP TABLE #TempUnusedIndexes

    结果如图:

    这类索引应该被Drop掉 

    最高维护代价的索引

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT                                                     
        DB_NAME() AS DatabaseName 
        , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , (s.user_updates ) AS [update usage] 
        , (s.user_seeks + s.user_scans + s.user_lookups) AS [Retrieval usage] 
        , (s.user_updates) - 
          (s.user_seeks + s.user_scans + s.user_lookups) AS [Maintenance cost] 
        , s.system_seeks + s.system_scans + s.system_lookups AS [System usage] 
        , s.last_user_seek 
        , s.last_user_scan 
        , s.last_user_lookup 
    INTO #TempMaintenanceCost 
    FROM   sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON  s.[object_id] = i.[object_id] 
        AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE 1=2 
    EXEC sp_MSForEachDB 'USE [?];                              
    INSERT INTO #TempMaintenanceCost 
    SELECT TOP 20 
        DB_NAME() AS DatabaseName 
        , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , (s.user_updates ) AS [update usage] 
        , (s.user_seeks + s.user_scans + s.user_lookups) 
                        AS [Retrieval usage] 
        , (s.user_updates) - 
    (s.user_seeks + user_scans + 
                             s.user_lookups) AS [Maintenance cost] 
        , s.system_seeks + s.system_scans + s.system_lookups AS [System usage] 
        , s.last_user_seek 
        , s.last_user_scan 
        , s.last_user_lookup 
    FROM   sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
        AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE s.database_id = DB_ID() 
        AND i.name IS NOT NULL 
        AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0 
        AND (s.user_seeks + s.user_scans + s.user_lookups) > 0 
    ORDER BY [Maintenance cost] DESC'                        
    SELECT top 20 * FROM #TempMaintenanceCost ORDER BY [Maintenance cost] DESC 
    DROP TABLE #TempMaintenanceCost

    结果如图:

    Maintenance cost高的应该被Drop掉

    使用频繁的索引

    --使用频繁的索引 
    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT                                           
        DB_NAME() AS DatabaseName 
            , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , (s.user_seeks + s.user_scans + s.user_lookups) AS [Usage] 
        , s.user_updates 
        , i.fill_factor 
    INTO #TempUsage 
    FROM sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
        AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE 1=2 
    EXEC sp_MSForEachDB 'USE [?];                               
    INSERT INTO #TempUsage 
    SELECT TOP 20 
        DB_NAME() AS DatabaseName 
        , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , (s.user_seeks + s.user_scans + s.user_lookups) AS [Usage] 
        , s.user_updates 
        , i.fill_factor 
    FROM   sys.dm_db_index_usage_stats s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
                AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE s.database_id = DB_ID() 
        AND i.name IS NOT NULL 
        AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0 
    ORDER BY [Usage] DESC'                                    
    SELECT TOP 20 * FROM #TempUsage ORDER BY [Usage] DESC 
    DROP TABLE #TempUsage

    结果如图

    3

     这类索引需要格外注意,不要在优化的时候干掉 

    碎片最多的索引

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT                                                     
        DB_NAME() AS DatbaseName 
        , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , ROUND(s.avg_fragmentation_in_percent,2) AS [Fragmentation %] 
    INTO #TempFragmentation 
    FROM sys.dm_db_index_physical_stats(db_id(),null, null, null, null) s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
        AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE 1=2 
    EXEC sp_MSForEachDB 'USE [?];                                
    INSERT INTO #TempFragmentation 
    SELECT TOP 20 
        DB_NAME() AS DatbaseName 
        , SCHEMA_NAME(o.Schema_ID) AS SchemaName 
        , OBJECT_NAME(s.[object_id]) AS TableName 
        , i.name AS IndexName 
        , ROUND(s.avg_fragmentation_in_percent,2) AS [Fragmentation %] 
    FROM sys.dm_db_index_physical_stats(db_id(),null, null, null, null) s 
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] 
        AND s.index_id = i.index_id 
    INNER JOIN sys.objects o ON i.object_id = O.object_id    
    WHERE s.database_id = DB_ID() 
      AND i.name IS NOT NULL 
      AND OBJECTPROPERTY(s.[object_id], ''IsMsShipped'') = 0 
    ORDER BY [Fragmentation %] DESC'                          
    SELECT top 20 * FROM #TempFragmentation ORDER BY [Fragmentation %] DESC 
    DROP TABLE #TempFragmentation

    结果如下:

    4

     这类索引需要Rebuild,否则会严重拖累数据库性能

    自上次SQL Server重启后,找出完全没有使用的索引

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT                                                 
        DB_NAME() AS DatbaseName 
        , SCHEMA_NAME(O.Schema_ID) AS SchemaName 
        , OBJECT_NAME(I.object_id) AS TableName 
        , I.name AS IndexName 
    INTO #TempNeverUsedIndexes 
    FROM sys.indexes I INNER JOIN sys.objects O ON I.object_id = O.object_id 
    WHERE 1=2 
    EXEC sp_MSForEachDB 'USE [?];                           
    INSERT INTO #TempNeverUsedIndexes 
    SELECT 
        DB_NAME() AS DatbaseName 
        , SCHEMA_NAME(O.Schema_ID) AS SchemaName 
        , OBJECT_NAME(I.object_id) AS TableName 
        , I.NAME AS IndexName 
    FROM sys.indexes I INNER JOIN sys.objects O ON I.object_id = O.object_id 
    LEFT OUTER JOIN sys.dm_db_index_usage_stats S ON S.object_id = I.object_id 
            AND I.index_id = S.index_id 
            AND DATABASE_ID = DB_ID() 
    WHERE OBJECTPROPERTY(O.object_id,''IsMsShipped'') = 0 
      AND I.name IS NOT NULL 
      AND S.object_id IS NULL' 
    SELECT * FROM #TempNeverUsedIndexes                         
    ORDER BY DatbaseName, SchemaName, TableName, IndexName 
    DROP TABLE #TempNeverUsedIndexes

    结果如图:

    5

     这类索引应该小心对待,不能一概而论,要看是什么原因导致这种问题

    查看索引统计的相关信息

    SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED 
    SELECT 
        ss.name AS SchemaName 
        , st.name AS TableName 
        , s.name AS IndexName 
        , STATS_DATE(s.id,s.indid) AS 'Statistics Last Updated' 
        , s.rowcnt AS 'Row Count' 
        , s.rowmodctr AS 'Number Of Changes' 
        , CAST((CAST(s.rowmodctr AS DECIMAL(28,8))/CAST(s.rowcnt AS 
    DECIMAL(28,2)) * 100.0) 
                                 AS DECIMAL(28,2)) AS '% Rows Changed' 
    FROM sys.sysindexes s 
    INNER JOIN sys.tables st ON st.[object_id] = s.[id] 
    INNER JOIN sys.schemas ss ON ss.[schema_id] = st.[schema_id] 
    WHERE s.id > 100 
      AND s.indid > 0 
      AND s.rowcnt >= 500 
    ORDER BY SchemaName, TableName, IndexName

    结果如下:

    6 

     因为查询计划是根据统计信息来的,索引的选择同样取决于统计信息,所以根据统计信息更新的多寡可以看出数据库的大体状况,20%的自动更新对于大表来说非常慢。

  • 相关阅读:
    听豆瓣架构变迁分享会总结
    业界对生成图片缩略图的做法归纳
    58和百姓网的技术学习
    减少存储过程封装业务逻辑-web开发与传统软件开发的思维模式不同
    网站速度问题排查与定位经验
    调度思想-现实中的事物与技术里面其实存在类似道理
    关于图片或者文件在数据库的存储方式归纳
    mysql单表体积和一个库设计多少张表为妥
    php的变量引用与销毁机制
    选择技术方案权衡时,考虑对其可控性很重要
  • 原文地址:https://www.cnblogs.com/davidhou/p/5153067.html
Copyright © 2020-2023  润新知