自动缺失索引创建语句

目录

介绍

背景

实现

使用代码

1. 函数——fn_Index_CreateIndexName

2. 查看——vw_Index_MissingIndex

3. 存储过程——usp_Index_MissingIndexCreationStatements

完整代码


介绍

有关索引的一个常见问题是选择在数据库上创建哪些索引以保证良好的性能。在此提示中,我想介绍有关此问题的解决方案,在本例中,我的所有代码都基于名为dm_db_missing_index_details

背景

在我们继续实现之前,也许了解更多有关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. 为每个索引创建语句的过程

我选择将这个系统划分为三个过程,但老实说,可以合并存储过程和视图。我个人没有选择这个解决方案,因为我想在创建索引之前从我的业务逻辑中检查它们有什么样的索引。

使用代码

1. 函数——fn_Index_CreateIndexName

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

  1. @equality_columns
  2. @equality_columns
  3. <a>@index_handlE</a>

该函数的目标是为要创建的每个索引创建一个唯一的名称。
所以首先,我们连接@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

2. 查看——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

3. 存储过程——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
	
	DECLARE @IndexName NVARCHAR(MAX)

	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

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

https://www.codeproject.com/Tips/1079651/Automatic-Missing-Indexes-Creation-Statements

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值