索引优化--汇总
思路 :先收集索引的信息,查看已有索引使用情况,删除不使用的索引,合并可以合并的索引,然后再重新收集信息,查看缺失的索引,最后建立索引。
第一步:收集索引信息
 SELECT o.name AS tableName,
        i.index_id ,
        i.name AS indexName,
        i.type AS indexType,
        i.type_desc AS indexType_Desc ,
        SUBSTRING(ikey.cols, 3, LEN(ikey.cols)) AS key_cols ,
        SUBSTRING(inc.cols, 3, LEN(inc.cols)) AS included_cols ,
        STATS_DATE(o.object_id, i.index_id) AS stats_date ,
        i.filter_definition
 FROM   sys.objects o
        JOIN sys.indexes i ON i.object_id = o.object_id
        CROSS  APPLY ( SELECT   ', ' + c.name + CASE ic.is_descending_key
                                                  WHEN 1 THEN ' DESC'
                                                  ELSE ''
                                                END
                       FROM     sys.index_columns ic
                                JOIN sys.columns c ON ic.object_id = c.object_id
                                                      AND ic.column_id = c.column_id
                       WHERE    ic.object_id = i.object_id
                                AND ic.index_id = i.index_id
                                AND ic.is_included_column = 0
                       ORDER BY ic.key_ordinal
                     FOR
                       XML PATH('')
                     ) AS ikey ( cols )
        OUTER  APPLY ( SELECT   ', ' + c.name
                       FROM     sys.index_columns ic
                                JOIN sys.columns c ON ic.object_id = c.object_id
                                                      AND ic.column_id = c.column_id
                       WHERE    ic.object_id = i.object_id
                                AND ic.index_id = i.index_id
                                AND ic.is_included_column = 1
                       ORDER BY ic.index_column_id
                     FOR
                       XML PATH('')
                     ) AS inc ( cols )
 WHERE o.type='U' AND i.type IN (1,2)
 ORDER BY o.name ,
        i.index_id  
第二步:收集索引的使用情况
CREATE TABLE [dbo].[index_usage](
	[DBname] [nvarchar](50) NULL,
	[TableName] [nvarchar](50) NULL,
	[IndexName] [nvarchar](100) NULL,
	[index_id] [int] NULL,
	[TotalWrites] [int] NULL,
	[TotalReads] [int] NULL,
	[Difference] [int] NULL,
	[last_user_seek] [datetime] NULL,
	[last_user_scan] [datetime] NULL,
	[last_user_lookup] [datetime] NULL,
	[last_user_update] [datetime] NULL,
	[RecordTime] [datetime] NULL
) ON [PRIMARY]
-------索引被使用的情况
INSERT  dbo.index_usage
        ( DBname ,
          TableName ,
          IndexName ,
          index_id ,
          TotalWrites ,
          TotalReads ,
          Difference ,
          last_user_seek ,
          last_user_scan ,
          last_user_lookup ,
          last_user_update ,
          RecordTime
        )
        SELECT  DB_NAME(ddius.database_id) DBname ,
                OBJECT_NAME(ddius.[object_id]) AS [Table Name] ,
                i.name AS [Index Name] ,
                i.index_id ,
                user_updates AS [Total Writes] ,
                user_seeks + user_scans + user_lookups AS [Total Reads] ,
                user_updates - ( user_seeks + user_scans + user_lookups ) AS [Difference] ,
                ddius.last_user_seek ,
                ddius.last_user_scan ,
                ddius.last_user_lookup ,
                ddius.last_user_update ,
                GETDATE()
        FROM    sys.indexes AS i WITH ( NOLOCK )
                LEFT JOIN sys.dm_db_index_usage_stats AS ddius WITH ( NOLOCK ) ON ddius.[object_id] = i.[object_id]
                                                              AND i.index_id = ddius.index_id
        WHERE   OBJECTPROPERTY(ddius.[object_id], 'IsUserTable') = 1
            --AND ddius.database_id = DB_ID('MultiCompany')
            --AND OBJECT_NAME(ddius.[object_id]) = 'AccountListOfPaltform'
                AND i.index_id > 1  --非聚集索引
        ORDER BY [Difference] DESC ,
                [Total Writes] DESC ,
                [Total Reads] ASC ;
第三步:索引使用详情
CREATE TABLE [dbo].[Index_query_plan](
	[database_name] [nvarchar](max) NULL,
	[TableName] NVARCHAR(max) NULL,
	[OBJECT_NAME] [nvarchar](max) NULL,
	[IndexName] [nvarchar](max) NULL,
	[objtype] [nvarchar](50) NULL,
	[query_plan] [xml] NULL,
	[use_counts] [int] NULL,
	[sql_text] [xml] NULL,
	[RecordTime] [datetime] NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; 
   WITH XMLNAMESPACES(DEFAULT 'http://schemas.microsoft.com/sqlserver/2004/07/showplan')  
   
INSERT  dbo.Index_query_plan
                ( database_name ,
                  OBJECT_NAME ,                  
                  objtype ,
                  query_plan ,
                  use_counts ,
                  sql_text ,
                  RecordTime
                )
    SELECT COALESCE(DB_NAME(p.dbid)  
       , p.query_plan.value('(//RelOp/OutputList/ColumnReference/@Database)[1]','nvarchar(128)'))  
         AS database_name  
      ,DB_NAME(p.dbid) + '.' + OBJECT_SCHEMA_NAME(p.objectid, p.dbid)  
        + '.' + OBJECT_NAME(p.objectid, p.dbid) AS object_name  
      ,cp.objtype  
      ,p.query_plan  
      ,cp.UseCounts AS use_counts        
      ,CAST('<?query --' + CHAR(13) + q.text + CHAR(13) + '--?>' AS XML) AS sql_text  
      ,GETDATE()
    FROM sys.dm_exec_cached_plans cp  
    CROSS APPLY sys.dm_exec_query_plan(cp.plan_handle) p  
    CROSS APPLY sys.dm_exec_sql_text(cp.plan_handle) AS q  
    WHERE cp.cacheobjtype = 'Compiled Plan'  
    AND p.query_plan.exist('//RelOp[@Parallel = "1"]') = 1  
    ORDER BY COALESCE(DB_NAME(p.dbid), p.query_plan.value('(//RelOp/OutputList/ColumnReference/@  
    Database)[1]','nvarchar(128)')), UseCounts DESC
----获取使用到有IndexName
UPDATE  A
SET     A.IndexName = CAST(A.query_plan.query('
    declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
    data(//IndexScan/Object/@Index)') AS VARCHAR(MAX)),
    A.tablename=CAST(A.query_plan.query('
    declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
    data(//IndexScan/Object/@Table)')AS VARCHAR(MAX))
--SELECT   CAST(A.query_plan.query('
--    declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
--    data(//IndexScan/Object/@Index)
--') AS VARCHAR(MAX)) IndexName,
--CAST(A.query_plan.query('
--    declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
--    data(//IndexScan/Object/@Table)
--') AS VARCHAR(MAX)) TableName,*
FROM    Index_query_plan A
WHERE   A.IndexName IS NULL
然后要优化某一条索引时,可以在存储的表中查询:
select * from Index_query_plan A
where A.query_plan.exist('//Object[@Index = "[索引名]"]') = 1
注意:
这个语句查询的是XML格式的执行计划,XML是大小写区分的,所以要严格按照索引名(在SSMS中查到的名字)来替换,否则查询不出来
第四步:缺失的索引
CREATE TABLE [dbo].[Index_optimize](
	[表] [nvarchar](255) NULL,
	[相等列] [nvarchar](255) NULL,
	[不相等列] [nvarchar](255) NULL,
	[包含列] [nvarchar](max) NULL,
	[总查询次数] [int] NULL,
	[平均百分比收益] [decimal](18, 2) NULL,
	[平均成本] [decimal](18, 2) NULL,
	[可能改进] [decimal](18, 2) NULL,
	[CreateSql] [nvarchar](max) NULL,
	[CreateTime] [datetime] NULL
) ON [PRIMARY]
SELECT *,GETDATE()
FROM    ( SELECT    statement AS 表 ,
                    equality_columns AS 相等列 ,
                    inequality_columns AS 不相等列 ,
                    included_columns AS 包含列 ,
                    user_scans + user_seeks AS 总查询次数 ,
                    avg_user_impact AS 平均百分比收益 ,
                    avg_total_user_cost AS 平均成本 ,
                    avg_total_user_cost * avg_user_impact * ( user_scans
                                                              + user_seeks ) AS 可能改进 ,
                    'CREATE INDEX [IX_' + obj.name + '_'
                    + CONVERT(VARCHAR(32), GS.group_handle) + '_'
                    + CONVERT(VARCHAR(32), D.index_handle) + ']' + ' ON '
                    + [statement] + ' (' + ISNULL(equality_columns, '')
                    + CASE WHEN equality_columns IS NOT NULL
                                AND inequality_columns IS NOT NULL THEN ','
                           ELSE ''
                      END + ISNULL(inequality_columns, '') + ')'
                    + ISNULL(' INCLUDE (' + included_columns + ')', '') AS Create_Index_Syntax
          FROM      sys.dm_db_missing_index_details AS D
                    INNER JOIN sys.dm_db_missing_index_groups G ON G.index_handle = D.index_handle
                    INNER JOIN sys.dm_db_missing_index_group_stats GS ON G.index_group_handle = GS.group_handle
                    INNER JOIN sys.objects AS obj ON obj.object_id = OBJECT_ID([statement])
                                                     AND obj.type = 'U'
        ) X
--WHERE   表 = '[MultiCompany].[Finance].[AccountListOfPaltform]'
-- --AND (相等列 LIKE '%ReceiveMethod %' OR 相等列 LIKE '%ReceiptsStatus%')
-- --AND 包含列 LIKE '%cost%'
ORDER BY 可能改进 DESC
原文:https://www.cnblogs.com/binghou/p/9109635.html
                    
                
                
            
        
浙公网安备 33010602011771号