The Problem

索引一直是优化查询性能的不二法门。其中一个最直接的问题便是当审查一个低性能查询语句时,检查索引是否在正确的地方或者加索引没有。运行一个batchjob查看索引碎片,必要时采取步骤优化索引碎片是日常维护程序中不可缺少的。

今天的主题便是如何判定数据库中的索引碎片和优化措施

我们经常会用到sys.dm_db_index_physical_stats表来查看索引信息

示例:

  1. USE AdventureWorks2014
  2. GO
  3.  
  4. DECLARE @database_name VARCHAR(100) = 'AdventureWorks2014';
  5. SELECT SD.name AS database_name ,
  6. SO.name AS object_name ,
  7. SI.name AS index_name ,
  8. IPS.index_type_desc ,
  9. IPS.page_count ,
  10. IPS.avg_fragmentation_in_percent
  11. FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, NULL) IPS
  12. INNER JOIN sys.databases SD ON SD.database_id = IPS.database_id
  13. INNER JOIN sys.indexes SI ON SI.index_id = IPS.index_id
  14. INNER JOIN sys.objects SO ON SO.object_id = SI.object_id
  15. AND IPS.object_id = SO.object_id
  16. WHERE alloc_unit_type_desc = 'IN_ROW_DATA'
  17. AND index_level = 0
  18. AND SD.name = @database_name
  19. ORDER BY IPS.avg_fragmentation_in_percent DESC;

当知道索引碎片信息以后,我们应该如何优化呢?或者在任何数据库中查看索引碎片和优化呢?

The Solution

优化索引有两种方案

  • Index Rebuild:

    When an index is rebuilt , it is completely replaced with a new copy of the index, built from scratch as though
    it were just newly created. In SQL Server Standard edition, this is an offline operation, meaning that it can
    cause contention while running.

  • Index Reorganization: 

    Reorganizing an index results in cleanup at the leaf level, reordering pages and reapplying the fill factor as
    necessary. This operation is always online, regardless of the edition of SQL Server you are running and can
    be interrupted at any time with no ill effects.

现在我们通过百分比来判定索引是rebulid还是reorganization

  1. IF OBJECT_ID('dbo.index_maintenance_demo','P') IS NOT NULL
  2. BEGIN
  3. DROP PROCEDURE dbo.index_maintenance_demo;
  4. END
  5.  
  6. SET ANSI_NULLS ON
  7. GO
  8. SET QUOTED_IDENTIFIER ON
  9. GO
  10.  
  11. CREATE PROCEDURE dbo.index_maintenance_demo
  12. @reorganization_percentage TINYINT = 10 ,
  13. @rebuild_percentage TINYINT = 35 ,
  14. @print_results_only BIT = 1
  15. AS
  16. BEGIN
  17. DECLARE @sql_command NVARCHAR(MAX) = '';
  18. DECLARE @parameter_list NVARCHAR(MAX) = '@reorganization_percentage TINYINT, @rebuild_percentage TINYINT'
  19. DECLARE @database_name NVARCHAR(MAX);
  20. DECLARE @database_list TABLE
  21. (
  22. database_name NVARCHAR(MAX) NOT NULL
  23. );
  24. INSERT INTO @database_list
  25. ( database_name
  26. )
  27. SELECT name
  28. FROM sys.databases
  29. WHERE databases.name NOT IN ( 'msdb', 'master', 'TempDB',
  30. 'model','ReportServer$SQL2014' );
  31. CREATE TABLE #index_maintenance
  32. (
  33. database_name NVARCHAR(MAX) ,
  34. schema_name NVARCHAR(MAX) ,
  35. object_name NVARCHAR(MAX) ,
  36. index_name NVARCHAR(MAX) ,
  37. index_type_desc NVARCHAR(MAX) ,
  38. page_count BIGINT ,
  39. avg_fragmentation_in_percent FLOAT ,
  40. index_operation NVARCHAR(MAX)
  41. );
  42.  
  43. SELECT @sql_command = @sql_command + '
  44. USE [' + database_name + ']
  45.  
  46. INSERT INTO #index_maintenance
  47. ( database_name ,
  48. schema_name ,
  49. object_name ,
  50. index_name ,
  51. index_type_desc ,
  52. page_count ,
  53. avg_fragmentation_in_percent ,
  54. index_operation
  55. )
  56. SELECT CAST(SD.name AS NVARCHAR(MAX)) AS database_name ,
  57. CAST(SS.name AS NVARCHAR(MAX)) AS schema_name ,
  58. CAST(SO.name AS NVARCHAR(MAX)) AS object_name ,
  59. CAST(SI.name AS NVARCHAR(MAX)) AS index_name ,
  60. IPS.index_type_desc ,
  61. IPS.page_count ,
  62. -- Be sure to filter as much as possible...this can return a lot of data if you dont filter by database and table.
  63. IPS.avg_fragmentation_in_percent ,
  64. CAST(CASE WHEN IPS.avg_fragmentation_in_percent >= @rebuild_percentage
  65. THEN ''REBUILD''
  66. WHEN IPS.avg_fragmentation_in_percent >= @reorganization_percentage
  67. THEN ''REORGANIZE''
  68. END AS NVARCHAR(MAX)) AS index_operation
  69. FROM sys.dm_db_index_physical_stats(NULL, NULL, NULL, NULL, NULL) IPS
  70. INNER JOIN sys.databases SD ON SD.database_id = IPS.database_id
  71. INNER JOIN sys.indexes SI ON SI.index_id = IPS.index_id
  72. INNER JOIN sys.objects SO ON SO.object_id = SI.object_id
  73. AND IPS.object_id = SO.object_id
  74. INNER JOIN sys.schemas SS ON SS.schema_id = SO.schema_id
  75. WHERE alloc_unit_type_desc = ''IN_ROW_DATA''
  76. AND index_level = 0
  77. AND SD.name = ''' + database_name + '''
  78. AND IPS.avg_fragmentation_in_percent >= @reorganization_percentage
  79. AND SI.name IS NOT NULL -- Only review index, not heap data.
  80. AND SO.is_ms_shipped = 0 -- Do not perform maintenance on system objects
  81. ORDER BY SD.name ASC;'
  82. FROM @database_list
  83. WHERE database_name IN ( SELECT name FROM sys.databases );
  84.  
  85. EXEC sp_executesql @sql_command, @parameter_list,
  86. @reorganization_percentage, @rebuild_percentage;
  87.  
  88. SELECT @sql_command = '';
  89. SELECT @sql_command = @sql_command + '
  90. USE ' + QUOTENAME(database_name) + '
  91. ALTER INDEX ' + QUOTENAME(index_name) + ' ON ' + QUOTENAME(schema_name) + '.' + QUOTENAME(object_name) + ' '
  92. + index_operation + ';'
  93. FROM #index_maintenance;
  94.  
  95. SELECT *
  96. FROM #index_maintenance
  97. ORDER BY avg_fragmentation_in_percent DESC;
  98.  
  99. IF @print_results_only = 1
  100. BEGIN
  101. PRINT @sql_command;
  102. END
  103. ELSE
  104. BEGIN
  105. EXEC sp_executesql @sql_command;
  106. END
  107.  
  108. DROP TABLE #index_maintenance;
  109. END
  110. GO

然后运行SP得到以下结果

  1. EXEC dbo.index_maintenance_demo @reorganization_percentage = 10, @rebuild_percentage = 35,
  2. @print_results_only = 1;

打印出来的SQL如下:

  1. USE [AdventureWorks2014]
  2. ALTER INDEX [PK_ProductCostHistory_ProductID_StartDate] ON [Production].[ProductCostHistory] REBUILD;
  3. USE [AdventureWorks2014]
  4. ALTER INDEX [AK_ProductDescription_rowguid] ON [Production].[ProductDescription] REBUILD;
  5. USE [AdventureWorks2014]
  6. ALTER INDEX [PK_DatabaseLog_DatabaseLogID] ON [dbo].[DatabaseLog] REBUILD;
  7. USE [AdventureWorks2014]
  8. ALTER INDEX [PK_ProductInventory_ProductID_LocationID] ON [Production].[ProductInventory] REBUILD;
  9. USE [AdventureWorks2014]
  10. ALTER INDEX [PK_ProductListPriceHistory_ProductID_StartDate] ON [Production].[ProductListPriceHistory] REBUILD;
  11. USE [AdventureWorks2014]
  12. ALTER INDEX [PK_SpecialOfferProduct_SpecialOfferID_ProductID] ON [Sales].[SpecialOfferProduct] REBUILD;
  13. USE [AdventureWorks2014]
  14. ALTER INDEX [AK_SpecialOfferProduct_rowguid] ON [Sales].[SpecialOfferProduct] REBUILD;
  15. USE [AdventureWorks2014]
  16. ALTER INDEX [PK_StateProvince_StateProvinceID] ON [Person].[StateProvince] REBUILD;
  17. USE [AdventureWorks2014]
  18. ALTER INDEX [PK_ProductModelProductDescriptionCulture_ProductModelID_ProductDescriptionID_CultureID] ON [Production].[ProductModelProductDescriptionCulture] REBUILD;
  19. USE [AdventureWorks2014]
  20. ALTER INDEX [AK_BillOfMaterials_ProductAssemblyID_ComponentID_StartDate] ON [Production].[BillOfMaterials] REORGANIZE;

有了这个SP,以后我们的维护工作就轻便了许多。

T-SQL Recipes之Index Defragmentation的更多相关文章

  1. Caused by: java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0

    1.错误描述 [ERROR:]2015-05-05 16:35:50,664 [异常拦截] org.hibernate.exception.GenericJDBCException: error ex ...

  2. java.sql.SQLException:Column Index out of range,0<1

    1.错误描述 java.sql.SQLException:Column Index out of range,0<1 2.错误原因 try { Class.forName("com.m ...

  3. java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2).

    java.sql.SQLException: Parameter index out of range (3 > number of parameters, which is 2). java. ...

  4. java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0).

    java.sql.SQLException: Parameter index out of range (1 > number of parameters, which is 0). at co ...

  5. java.io.IOException: java.sql.SQLException: ORA-01502: index 'BTO.PK_xxxxx' or partition of such index is in unusable state

    最近由于数据库的全备出问题了,所以一直在观察. 刚好发现很多不需要的数据,就删了几百个G的数据吧. 今天突然就报这个问题. java.io.IOException: java.sql.SQLExcep ...

  6. sql server中index的REBUILD和REORGANIZE的区别及工作方式

    sql server中index的REBUILD和REORGANIZE 转自:https://www.cnblogs.com/flysun0311/archive/2013/12/05/3459451 ...

  7. ylb:SQL 索引(Index)

    ylbtech-SQL Server: SQL Server-SQL 索引(Index) SQL 索引(Index). ylb:索引(Index) 返回顶部 --=================== ...

  8. SQL Server 索引(index) 和 视图(view) 的简单介绍和操作

    --索引(index)和视图(view)-- --索引(index)----概述: 数据库中的索引类似于书籍的目录,他以指针形式包含了表中一列或几列组合的新顺序,实现表中数据库的逻辑排序.索引创建在数 ...

  9. sql server中index的REBUILD和REORGANIZE

    参考文献: http://technet.microsoft.com/en-us/library/ms188388.aspx 正文 本文主要讲解如何使用alter index来rebuild和reor ...

随机推荐

  1. runtime第二部分成员变量和属性

    接上一篇 http://www.cnblogs.com/ddavidXu/p/5912306.html 转载来源http://www.jianshu.com/p/6b905584f536 http:/ ...

  2. word20161225

    Waiting for Call / 等待呼叫 wallpaper / 墙纸 WAN, wide area network / 广域网 warning level / 警告级别 Web folder ...

  3. CSS布局 ——从display,position, float属性谈起

    页面布局,或者是在页面上做些小效果的时候经常会用到 display,position和float 属性,如果对它们不是很了解的话,很容易出现一些莫名其妙的效果,痛定思痛读了<CSS Master ...

  4. C#夯实基础之接口(《CLR via C#》读书笔记)

    一. 接口的类型 接口是引用类型.因此从值类型赋值给接口是需要装箱的.如下所示: class Program { static void Main(string[] args) { ISay catS ...

  5. ubuntu 好玩多了

    从一开始的咒骂,到慢慢的喜欢,ubuntu比CentOs可玩多了.

  6. testng 失败自动截图

    testng执行case failed ,testng Listener会捕获执行失败,如果要实现失败自动截图,需要重写Listener的onTestFailure方法 那么首先新建一个Listene ...

  7. php二进制安全的含义

    PHP里,有string的概念.string里,每个字符的大小为byte(与PHP相比,Java的每个字符为Character,是UTF8字符,C语言的每个字符可以在编译时选择). byte里,有AS ...

  8. Mybatis 总结

    1.如何传递多个参数 mybatis中,如果接口有多个参数,那么在mapper.xml中,可以通过#{0,VARCHAR},#{1,VARCHAR}或#{param1,VARCHAR},#{param ...

  9. cornerstone知识点

    CornerStone使用教程(配置SVN,HTTP及svn简单使用) 发布时间:2015-01-02 19:54   作者:芳仔小脚印    来源:开源中国 CornerStone是Mac OS X ...

  10. 51nod1265(判断四个点是否共面)

    题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1265 题意:中文题诶- 思路:假设现有a, b, c, d四 ...