新西兰服务器

如何使用系统SQL实体自动创建非聚集索引


如何使用系统SQL实体自动创建非聚集索引

发布时间:2021-11-23 17:56:23 来源:高防服务器网 阅读:98 作者:小新 栏目:编程语言

小编给大家分享一下如何使用系统SQL实体自动创建非聚集索引,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!

引言

一直以来,关于索引的常见问题是:判断哪部分索引对保证数据库的良好性能是必需的。在本文中,笔者将提供针对该问题的解决方案。本文用例中的所有代码都基于名为dm_db_missing_index_details 的 SQL Server 系统视图。

背景

在开始安装前,进一步了解 dm_db_missing_index_details 会更有益处。

dm_db_missing_index_details 会返回缺失索引的细节信息。在本文中,我们将更关注以下几列:

  • index_handle:它是一个独特的跨服务器标识符,并且标志一个特定的缺失索引。

  • equality_columns:包含用于相等谓词的所有列

  • inequality_columns:包含用于其他比较的所有列

  • included columns索引中所包含的查询必要出现列

  • statement: 补充完整索引缺失的表名

实现

本系统的实现基于以下三个实体:

  1. 一个可以计算出待创建索引名称的简单函数

  2. 一个用于简化 dm_db_missing_index_details的用户视图

  3. 一个为每个索引创建声明的进程

笔者选择将这个系统分为三段进程,但实际上合并存储过程和视图也是可行的。笔者之所以没有选择后一种做法是因为想在创建索引之前先从业务逻辑检查一下存在哪些索引。

使用代码

函数 fn_Index_CreateIndexName 
在这个函数中,有三个输入参数:

     @equality_columns       @equality_columns       @index_handlE

该函数的目的是为每个期望创建的索引都创建一个唯一名称。

因此,首先拼接@equality_columns@equality_columns两个输入变量,如果拼接后所得结果超过120个字符,那就截取至第120个字符。

为什么是120个字符?

因为在SQL Server中,命名最大长度为128个字符。这个函数在 @index_handlE 名字结尾添加字段以便保证唯一的索引名。

    CREATE FUNCTION [dbo].[fn_Index_CreateIndexName] (@equality_columns NVARCHAR(4000), _      @Inequality_columns NVARCHAR(4000), @index_handlE INT) RETURNS VARCHAR(128)      AS      BEGIN      DECLARE @IndexName NVARCHAR(255)      SET @IndexName = ISNULL(@equality_columns,@Inequality_columns)      SET @IndexName = LTRIM(REPLACE(@IndexName,'[','_'))      SET @IndexName = RTRIM(REPLACE(@IndexName,']','_'))      SET @IndexName = REPLACE(@IndexName,',','')      SET @IndexName = REPLACE(@IndexName,'_ _','_')      IF LEN(@IndexName) > 120      BEGIN          SET @IndexName = SUBSTRING(@IndexName,0,120)      END        SET @IndexName = @IndexName + CAST(@index_handlE AS NVARCHAR(15))      RETURN @IndexName       END

视图 vw_Index_MissingIndex 
该视图基于dm_db_missing_index_details和 sys.databases 表,并使用fn_Index_CreateIndexName 函数来计算缺失的索引名。

    CREATE VIEW [dbo].[vw_Index_MissingIndex]      AS      SELECT  '[' + d.name + ']' as DBName,              [dbo].[fn_Index_CreateIndexName]_              (mid.equality_columns,mid.Inequality_columns,mid.index_handlE) AS ID,              REPLACE(mid.equality_columns,',',' ASC,') AS equality_columns,              REPLACE(mid.Inequality_columns,',',' ASC,') AS Inequality_columns,              mid.Included_columns,              mid.[statement]      FROM sys.dm_db_missing_index_details mid      INNER JOIN sys.databases d      on d.database_id = mid.database_id

存储过程 usp_Index_MissingIndexCreationStatements 
该存储过程基于 vw_Index_MissingIndex,并且输出索引创建语句。

    CREATE PROCEDURE [dbo].[usp_Index_MissingIndexCreationStatements]      AS      DECLARE @IndexCreationPlaceholder_Start  AS NVARCHAR(MAX)      DECLARE @IndexCreationPlaceholder_End  AS NVARCHAR(MAX)      -- PREPARE PLACEHOLDER      SET @IndexCreationPlaceholder_Start = 'IF NOT EXISTS(SELECT * _      FROM {2}.sys.indexes WHERE [name] = ''IX_{0}'' )                      BEGIN                      CREATE NONCLUSTERED INDEX [IX_{0}] ON {1}'      SET @IndexCreationPlaceholder_End = ' WITH (PAD_INDEX = OFF, _      STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, _      ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]                      END;' + char(13) + char(10)      -- STATEMENT CREATION      SELECT          DBName,          CASE          WHEN NOT mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THEN                      REPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _                      mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)                      + '                         ( ' +                         COALESCE(mid.equality_columns,'') +                         ' ASC,' +                          COALESCE(mid.Inequality_columns,'') +                         ' ASC                      )' +                      COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')                      + @IndexCreationPlaceholder_End              WHEN mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THEN                      REPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,_                      '{0}', mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)                      + '                         ( ' +                         COALESCE(mid.Inequality_columns,'') +                         ' ASC                      ) ' +                      COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')                      + @IndexCreationPlaceholder_End          WHEN NOT mid.equality_columns IS NULL AND mid.Inequality_columns IS NULL THEN                  REPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _                  mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)                  + '                     ( ' +                 COALESCE(mid.equality_columns,'') +  ' ASC                      ) ' +                  COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')                  + @IndexCreationPlaceholder_End          ELSE NULL      END AS Index_Creation_Statement,          ' DROP INDEX [IX_' + mid.ID  + '] ON ' + mid.[statement]  _          +  + char(13) + char(10) AS Index_Drop_Statement      FROM [dbo].[vw_Index_MissingIndex] AS mid

完整代码

    -- CREATE FUNCTION fn_Index_CreateIndexName      CREATE FUNCTION [dbo].[fn_Index_CreateIndexName] (@equality_columns NVARCHAR(4000), _      @Inequality_columns NVARCHAR(4000), @index_handlE INT) RETURNS VARCHAR(128)      AS      BEGIN              DECLAR      E @IndexName NVARCHAR(MAX)          SET @IndexName = ISNULL(@equali      ty_columns,@Inequality_columns)      SET @IndexName = LTRIM(REPLACE(@IndexName,'[','_'))      SET @IndexName = RTRIM(REPLACE(@IndexName,']','_'))      SET @IndexName = REPLACE(@IndexName,',','')      SET @IndexName = REPLACE(@IndexName,'_ _','_')          IF LEN(@IndexName) > 120          BEGIN              SET @IndexName = SUBSTRING(@IndexName,0,120)          END            SET @IndexName = @IndexName + CAST(@index_handlE AS NVARCHAR(15))          RETURN @IndexName       END      GO      -- CREATE FUNCTION vw_Index_MissingIndex      CREATE VIEW [dbo].[vw_Index_MissingIndex]       AS      SELECT  '[' + d.name + ']' as DBName,              [dbo].[fn_Index_CreateIndexName]_              (mid.equality_columns,mid.Inequality_columns,mid.index_handlE) AS ID,              REPLACE(mid.equality_columns,',',' ASC,') AS equality_columns,              REPLACE(mid.Inequality_columns,',',' ASC,') AS Inequality_columns,              mid.Included_columns,              mid.[statement]      FROM sys.dm_db_missing_index_details mid      INNER JOIN sys.databases d      on d.database_id = mid.database_id      GO      CREATE PROCEDURE [dbo].[usp_Index_MissingIndexCreationStatements]      AS      DECLARE @IndexCreationPlaceholder_Start  AS NVARCHAR(MAX)      DECLARE @IndexCreationPlaceholder_End  AS NVARCHAR(MAX)      -- PREPARE PLACEHOLDER      SET @IndexCreationPlaceholder_Start = 'IF NOT EXISTS_      (SELECT * FROM {2}.sys.indexes WHERE [name] = ''IX_{0}'' )                      BEGIN                      CREATE NONCLUSTERED INDEX [IX_{0}] ON {1}'      SET @IndexCreationPlaceholder_End = ' WITH (PAD_INDEX = OFF, _      STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, _      ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]                      END;' + char(13) + char(10)      -- STATEMENT CREATION      SELECT          DBName,          CASE          WHEN NOT mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THEN                      REPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _                      mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)                      + '                         ( ' +                         COALESCE(mid.equality_columns,'') +                         ' ASC,' +                          COALESCE(mid.Inequality_columns,'') +                         ' ASC                      )' +                      COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')                      + @IndexCreationPlaceholder_End              WHEN mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THEN                      REPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _      mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)                  + '                     ( ' +                     COALESCE(mid.Inequality_columns,'') +                     ' ASC                  ) ' +                  COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')                  + @IndexCreationPlaceholder_End          WHEN NOT mid.equality_columns IS NULL AND mid.Inequality_columns IS NULL THEN                  REPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _                  mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)                  + '                     ( ' +                 COALESCE(mid.equality_columns,'') +  ' ASC                      ) ' +                  COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')                  + @IndexCreationPlaceholder_End          ELSE NULL      END AS Index_Creation_Statement,      ' DROP INDEX [IX_' + mid.ID  + '] ON ' + mid.[statement]  _          +  + char(13) + char(10) AS Index_Drop_Statement      FROM [dbo].[vw_Index_MissingIndex] AS mid      GO

以上是“如何使用系统SQL实体自动创建非聚集索引”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注高防服务器网行业资讯频道!

[微信提示:高防服务器能助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。

[图文来源于网络,不代表本站立场,如有侵权,请联系高防服务器网删除]
[