【编者按】 本文主要介绍使用系统 SQL 实体自动创建非聚集(non-clustered)索引。作者为意大利软件工程师 GhostHost(笔名)。

本文系 OneAPM 工程师编译呈现,以下为正文。

引言

一直以来,关于索引的常见问题是:判断哪部分索引对保证数据库的良好性能是必需的。在本文中,笔者将提供针对该问题的解决方案。本文用例中的所有代码都基于名为 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
在这个函数中,有三个输入参数:

    1.  @equality_columns2.  @equality_columns3.  @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)ASBEGINDECLARE @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) > 120BEGINSET @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]ASSELECT  '[' + 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 midINNER JOIN sys.databases don d.database_id = mid.database_id

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

    CREATE PROCEDURE [dbo].[usp_Index_MissingIndexCreationStatements]ASDECLARE @IndexCreationPlaceholder_Start  AS NVARCHAR(MAX)DECLARE @IndexCreationPlaceholder_End  AS NVARCHAR(MAX)-- PREPARE PLACEHOLDERSET @IndexCreationPlaceholder_Start = 'IF NOT EXISTS(SELECT * _FROM {2}.sys.indexes WHERE [name] = ''IX_{0}'' )BEGINCREATE 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 CREATIONSELECTDBName,CASEWHEN NOT mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THENREPLACE(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_EndWHEN mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THENREPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,_'{0}', mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)+ '( ' +COALESCE(mid.Inequality_columns,'') +' ASC) ' +COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')+ @IndexCreationPlaceholder_EndWHEN NOT mid.equality_columns IS NULL AND mid.Inequality_columns IS NULL THENREPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)+ '( ' +COALESCE(mid.equality_columns,'') +  ' ASC) ' +COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')+ @IndexCreationPlaceholder_EndELSE NULLEND AS Index_Creation_Statement,' DROP INDEX [IX_' + mid.ID  + '] ON ' + mid.[statement]  _+  + char(13) + char(10) AS Index_Drop_StatementFROM [dbo].[vw_Index_MissingIndex] AS mid

完整代码

    -- CREATE FUNCTION fn_Index_CreateIndexNameCREATE FUNCTION [dbo].[fn_Index_CreateIndexName](@equality_columns NVARCHAR(4000), _@Inequality_columns NVARCHAR(4000), @index_handlE INT) RETURNS VARCHAR(128)ASBEGINDECLARE @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) > 120BEGINSET @IndexName = SUBSTRING(@IndexName,0,120)END  SET @IndexName = @IndexName + CAST(@index_handlE AS NVARCHAR(15))RETURN @IndexName ENDGO-- CREATE FUNCTION vw_Index_MissingIndexCREATE VIEW [dbo].[vw_Index_MissingIndex] ASSELECT  '[' + 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 midINNER JOIN sys.databases don d.database_id = mid.database_idGOCREATE PROCEDURE [dbo].[usp_Index_MissingIndexCreationStatements]ASDECLARE @IndexCreationPlaceholder_Start  AS NVARCHAR(MAX)DECLARE @IndexCreationPlaceholder_End  AS NVARCHAR(MAX)-- PREPARE PLACEHOLDERSET @IndexCreationPlaceholder_Start = 'IF NOT EXISTS_(SELECT * FROM {2}.sys.indexes WHERE [name] = ''IX_{0}'' )BEGINCREATE 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 CREATIONSELECTDBName,CASEWHEN NOT mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THENREPLACE(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_EndWHEN mid.equality_columns IS NULL AND NOT mid.Inequality_columns IS NULL THENREPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)+ '( ' +COALESCE(mid.Inequality_columns,'') +' ASC) ' +COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')+ @IndexCreationPlaceholder_EndWHEN NOT mid.equality_columns IS NULL AND mid.Inequality_columns IS NULL THENREPLACE(REPLACE(REPLACE(@IndexCreationPlaceholder_Start,'{0}', _mid.ID),'{1}',mid.[statement]),'{2}',mid.DBName)+ '( ' +COALESCE(mid.equality_columns,'') +  ' ASC) ' +COALESCE('INCLUDE ( ' + mid.Included_columns + ' ) ','')+ @IndexCreationPlaceholder_EndELSE NULLEND AS Index_Creation_Statement,' DROP INDEX [IX_' + mid.ID  + '] ON ' + mid.[statement]  _+  + char(13) + char(10) AS Index_Drop_StatementFROM [dbo].[vw_Index_MissingIndex] AS midGO

OneAPM 助您轻松锁定 .NET 应用性能瓶颈,通过强大的 Trace 记录逐层分析,直至锁定行级问题代码。以用户角度展示系统响应速度,以地域和浏览器维度统计用户使用情况。想技术文章,请访问 OneAPM 官方博客。

本文转自 OneAPM 官方博客

原文地址:http://www.codeproject.com/Tips/1079651/Automatic-Missing-Non-Clustered-Creation-Statement

缺失索引自动创建语句相关推荐

  1. 如何导出存储过程、函数、包和触发器的定义语句?如何导出表和索引的创建语句?...

    Oracle中如何导出存储过程.函数.包和触发器的定义语句?如何导出表的结构?如何导出索引的创建语句? QQ群里有人问:如何导出一个用户下的存储过程?   麦苗答:方法有多种,可以使用DBMS_MET ...

  2. mysql数据库索引的创建语句

    单列索引 CREATE INDEX 索引名 ON 表名(列名);组合索引创建 create unique index 索引名 on 表名(列名1,列名2--)

  3. Oracle中查询用户表/索引/视图的创建语句

    1.查询当前用户下表的创建语句 select dbms_metadata.get_ddl('TABLE','ux_future') from dual; 2.查询其他用户下表的创建语句 select ...

  4. mysql 排序字段是否需要建索引_MySQL索引详解(优缺点,何时需要/不需要创建索引,索引及sql语句的优化)...

    一.什么是索引? 索引是对数据库表中的一列或多列值进行排序的一种结构,使用索引可以快速访问数据库表中的特定信息. 二.索引的作用? 索引相当于图书上的目录,可以根据目录上的页码快速找到所需的内容,提高 ...

  5. 使用navicat for mysql 创建外键foreign keys时,总会自动创建索引indexs

    使用navicat for mysql 创建外键foreign keys时,总会自动创建索引indexs.如果删除这个索引就会提示错误error 1553:cann't drop index-:nee ...

  6. mysql修改索引语句_mysql——创建索引、修改索引、删除索引的命令语句

    查看表中已经存在 index:show index from table_name; 创建和删除索引索引的创建可以在CREATE TABLE语句中进行,也可以单独用CREATE INDEX或ALTER ...

  7. MySQL创建各种索引的SQL语句

    主键索引:创建表时自动创建 { 聚集索引:一个表中只有一个聚集索引 } 唯一索引: CREATE UNIQUE INDEX unique_index_warn[索引名称] ON cas_alarm[表 ...

  8. Python读取多个excel文件(删除字段、数据格式转换、dataframe多表合并)并写入ElasticSearch实战(自动创建索引、写入ElasticSearch、探索性数据分析)

    Python读取多个excel文件(删除字段.数据格式转换.dataframe多表合并)并写入ElasticSearch实战(自动创建索引.写入ElasticSearch.探索性数据分析) 目录

  9. oracle查看创建索引语句,ORACLE下如何获得全部的索引创建语句

    ORACLE下如何获得全部的索引创建语句 ORACLE下如何获得全部的索引创建语句 今天打算将一个数据库的索引在另一个测试库上重新创建一遍,研究了一下. set pagesize 0 set long ...

  10. oracle 创建clob类型字段的索引,LOB字段相关概念(自动创建LOB索引段和重建索引方法)...

    LOBs,或Large Objects字段,是Oracle中用于处理存储非字符数据推荐的一种字段类型,例如mp3,video,图片,和long字符串数据.二进制大对象,或BLOBs,字符大对象,或CL ...

最新文章

  1. 【Web安全】PHP与Web表单交互-POST方法与GET方法(看不懂你来打我)
  2. 深入理解ROS技术 【1】ROS下的模块详解(1-65)
  3. 洛谷 P1703 那个什么密码2
  4. 关于优酷开放SDk之setOnAdCountListener和setOnNetworkSppedListener
  5. SPOJ - PHRASES Relevant Phrases of Annihilation(后缀数组+二分)
  6. 微信公众号开发--微信JS-SDK扫一扫功能
  7. openstack 功能_OpenStack Juno的新功能
  8. c语言人事档案管理系统简单的,人事档案统一标准管理系统c语言.doc
  9. fortran95查询字符串出现次数子程序
  10. js链接oracle数据库语法,js连接oracle数据库
  11. 基于STM32+华为云IOT设计的云平台监控系统
  12. Subset sum problem
  13. matlab输入数据作方程,用MATLAB函数编写并求解微分方程
  14. HDU4544 湫湫系列故事――消灭兔子
  15. 6.oop-类和对象
  16. 51Nod - 1247 找规律
  17. 解决:RuntimeError: CUDA out of memory. Tried to allocate 64.00 MiB (GPU 0; 4.00 GiB total capacity; 2
  18. Marvell 交换芯片DSA(分布式交换架构)功能介绍
  19. 2022年天猫双11活动时间及玩法
  20. IDEA版SpringBoot全教程 08 会员管理系统(中)

热门文章

  1. matlab仿真之大尺度衰落因子2--小区间
  2. AS 更新项目gradle方法
  3. Java 重载和重写
  4. java.io.FileWriter class doesn’t use UTF-8 by default
  5. xshell与虚拟机VMware中centos6.7系统突然连不上
  6. 操作系统课设 Nachos 实验六、七、八:Nachos 用户程序与系统调用、地址空间的扩展、系统调用 Exec() 与 Exit()
  7. 【带权并查集 —— 是否说谎】Parity game【POJ 1733】
  8. 能力提升综合题单 Part 8.9.1 最大流
  9. 对象三大特性:封装、继承、多态。通俗易懂!!看完还不懂来打我!!!超详细!!涉及各种重要基础
  10. 343.整数拆分(力扣leetcode) 博主可答疑该问题