要点:

-       检查索引碎片fragmentation: average percentage, pagecount

-       采用ALTER INDEX REBUILD指令

-       手动设置Timeout参数

-       设置计数器以控制SSMS停止响应时间

-       增加暂停以释放被挂起的进程

-       EXEC sp_who2以检查死锁

  1. 背景

有许多系统把部分逻辑写在数据库中,随着时间的流逝,数据和索引逐渐增加,因而数据库的性能将逐渐减小。

其中一个重要的影响因素是索引。

当数据和索引增加时,其碎片化程度也将随之增加。

根据微软的文档“Reorganizingand Rebuilding Indexes(https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2005/ms189858(v=sql.90))”, 当碎片化率在5%~30%时,我们应当使用REORGANIZE指令重组索引,当碎片化率超过30%时,我们应当REBUILD重建索引。

我们可以使用下述SQL列出所有碎片化率超过30%的索引:

-------------------------------------------------------------------------------------

SELECT dbschemas.[name]AS 'Schema'

,dbtables.[name] AS 'Table'

,dbindexes.[name] AS 'Index'

,indexstats.avg_fragmentation_in_percent

,indexstats.page_count

FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats

INNER JOIN sys.tables dbtables ONdbtables.[object_id] =indexstats.[object_id]

INNER JOIN sys.schemas dbschemas ONdbtables.[schema_id] =dbschemas.[schema_id]

INNER JOIN sys.indexes AS dbindexesON dbindexes.[object_id]= indexstats.[object_id]

ANDindexstats.index_id =dbindexes.index_id

WHERE indexstats.database_id= DB_ID()

AND indexstats.avg_fragmentation_in_percent> 30

--ANDdbschemas.[name] = 'dbo'

--ANDdbtables.[name] = 'RPV_MAGPLANBEL'

--ORDERBY indexstats.page_count DESC;

ORDER BY indexstats.avg_fragmentation_in_percent DESC;

-------------------------------------------------------------------------------------

另有一个重要参数是page_count,即索引页数,每页约有8KB数据,因此当页数非常大时,意味着此索引的重建时间也会很长。

2.    需要考虑的因素

  • 使用ALTER INDEX index_name还是ALTERINDEX ALL

使用ALTER INDEX index_name ON Table REBUILD只能重建指定索引。

使用ALTER INDEX ALL ON Table REBUILD能够重建此表的所有索引,但是也需要更长的等待时间,因此在重建过程中指向这些索引的新SQL将被挂起SUSPENDED等待。

  • 手动设置远程timeout,以避免被服务器超时断开,如执行以下SQL:

EXEC sp_configure'remote query timeout', 600 ; -- 设置为600秒

RECONFIGURE ;

因为重建过程可能较长,超出默认的TIMEOUT,因此最好手动设置此项参数。

  • 设置计数器以控制停止响应时间

即使我们在SSMS中通过PRINT()指令输出中间过程的信息,相关消息也只有在SQL指令块执行完毕之后才会显示。

在SQL执行过程中,消息框是空白的,因而在此期间我们无从得知SQL执行的具体情况。

因而最好将完整的执行过程分割成许多个小的过程,我们可以通过计数器予以控制。

现在我们修改一个查询碎片化的SQL,采用page_count逆向排序:

-------------------------------------------------------------------------------------

SELECT --dbschemas.[name] AS'Schema',

dbtables.[name]AS 'Table',

dbindexes.[name]AS 'Index',

indexstats.avg_fragmentation_in_percent,

indexstats.page_count

FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats

INNER JOIN sys.tables dbtables ONdbtables.[object_id] =indexstats.[object_id]

INNER JOIN sys.schemas dbschemas ONdbtables.[schema_id] =dbschemas.[schema_id]

INNER JOIN sys.indexes AS dbindexesON dbindexes.[object_id]= indexstats.[object_id]

ANDindexstats.index_id =dbindexes.index_id

WHERE indexstats.database_id= DB_ID()

ANDindexstats.avg_fragmentation_in_percent > 30

ANDdbschemas.[name] ='dbo'

--ANDdbtables.[name] = 'RPV_MAGPLANBEL'

ANDdbindexes.[name] ISNOT NULL

ORDER BYindexstats.page_count DESC;

--ORDERBY indexstats.avg_fragmentation_in_percent DESC;

-------------------------------------------------------------------------------------

对于page count较大(如超过10万)的索引,我们可以每次只重建1个索引。

对于page count较小的索引,我们可以根据情况设置一个较大的计数器数据。

  • 设置暂停以释放挂起的进程

当我们利用游标,在同一个进程中执行多个REBUILD指令时,我们应当在两个指令间设置至少5秒的暂停时间,此时间可用来释放被系统挂起的进程(这些进程会引用到正在重建的索引)。

相关SQL:

WAITFOR DELAY '00:00:05'; -- 暂停5秒

  • 在REBUILD之前和进行中检查实时死锁deadlocks

相关指令:

EXECsp_who2

我们可以看到死锁的进程(Status=SUSPENDED, 或BlkBy IS NOT NULL), BlkBy指向引起死锁的进程。

只有确保无死锁发生时,才能执行REBUILD。

另一个检查死锁的SQL:

SELECT *

FROM sys.dm_exec_requests

WHERE DB_NAME(database_id) = 'KBS_FDM' –数据库名

AND blocking_session_id <>0;

3.    优化过的SQL:

-------------------------------------------------------------------------------------

Declare @getTables CURSOR; -- Cursor to list out allindexes have frag % > 30

Declare @TableName varchar(255);

Declare @IndexName varchar(255);

Declare @command nvarchar(4000); -- Detail ALTER INDEX command

DECLARE @DT NVARCHAR(50);   -- Datetime to printout

DECLARE @i INT;-- Counter

-- setremote time out

EXEC sp_configure'remote query timeout', 600 ;

RECONFIGURE ;

SELECT @DT = CONVERT(NVARCHAR, GETDATE(), 121);--YYYY-MM-DD HH:MI:SS

PRINT(@DT);

PRINT('Rebuilding Index started.');

PRINT('');

--SET@getTables = CURSOR for SELECT name FROM sys.objects WHERE type = (N'U');

--EXECsp_who2 -- to check existing deadlock(BlkBy)

SET @i = 0;

SET @getTables = CURSOR for

SELECT --dbschemas.[name] AS'Schema',

dbtables.[name]AS 'TableName',

dbindexes.[name]AS 'IndexName'

--indexstats.avg_fragmentation_in_percent,

--indexstats.page_count

FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, NULL) AS indexstats

INNER JOIN sys.tables dbtables ONdbtables.[object_id] =indexstats.[object_id]

INNER JOIN sys.schemas dbschemas ONdbtables.[schema_id] =dbschemas.[schema_id]

INNER JOIN sys.indexes AS dbindexesON dbindexes.[object_id]= indexstats.[object_id]

ANDindexstats.index_id =dbindexes.index_id

WHERE indexstats.database_id= DB_ID()

ANDindexstats.avg_fragmentation_in_percent > 30

ANDdbschemas.[name] ='dbo'

--AND dbtables.[name]= 'RPV_MAGPLANBEL'

ANDdbindexes.[name] ISNOT NULL

ORDER BY indexstats.page_count DESC;

--ORDERBY indexstats.avg_fragmentation_in_percent DESC;

OPEN @getTables;

FETCH NEXT FROM @getTables into @TableName,@IndexName;

--WHILE @@FETCH_STATUS= 0

WHILE @i < 1 AND @@FETCH_STATUS = 0-- Set @i to biggernumber when page count is getting smaller

BEGIN;

SELECT@DT = CONVERT(NVARCHAR, GETDATE(), 121);--YYYY-MM-DD HH:MI:SS

PRINT(@DT);

--set @command= N'ALTER INDEX ALL ON ' + @TableName + N' REBUILD;';   -- WITH (ONLINE=ON);'; for enterprise version only

set@command = N'ALTERINDEX ' + @IndexName + N' ON ' + @TableName + N' REBUILD;';

PRINT(@command);

--PRINT('');

--WAITFORDELAY '00:00:01';

BEGIN TRY

EXEC (@command);

SELECT@DT = CONVERT(NVARCHAR, GETDATE(), 121);--YYYY-MM-DD HH:MI:SS

PRINT(@DT);

PRINT('Rebuilding Indexcompleted.');

PRINT('');

END TRY

BEGIN CATCH

SELECT@DT = CONVERT(NVARCHAR, GETDATE(), 121);--YYYY-MM-DD HH:MI:SS

PRINT(@DT);

PRINT'CATCHED!';

END CATCH;

WAITFOR DELAY '00:00:05';   -- wait 5s to release suspended sessions

FETCH NEXT FROM @getTables into @TableName,@IndexName;

SET @i = @i + 1;

END;

CLOSE @getTables;

DEALLOCATE @getTables;

SELECT @DT = CONVERT(NVARCHAR, GETDATE(), 121);--YYYY-MM-DD HH:MI:SS

PRINT(@DT);

PRINT('All indexes rebuilt.');

-------------------------------------------------------------------------------------

4.     关于WITH(ONLINE=ON)参数

在运行ALTERINDEX (ALL) REBUILD指令时,有一个可选参数ONLINE。

如果设置ONLINE=ON,则在重建过程的大部分时间旧索引依然可用,因而对生产环境的影响较小,但是此参数仅适用于企业版SQL SERVER。

ssms 缺少索引信息_SQLServer索引重建相关推荐

  1. sqlserver和mysql索引结构_sqlserver 索引的一些总结

    1.1.1 摘要 如果说要对数据库进行优化,我们主要可以通过以下五种方法,对数据库系统进行优化. 1. 计算机硬件调优 2. 应用程序调优 3. 数据库索引优化 4. SQL语句优化 5. 事务处理调 ...

  2. ssms 缺少索引信息_MySQL3:索引

    什么是索引 索引是对数据库表中一列或者多列的值进行排序的一种结构,所引用于快速找出在某个列中有一特定值的行.不使用索引,MySQL必须从第一条记录开始读完整个表,直到找出相关的行.表越大,查询数据所花 ...

  3. [推荐]数据库索引碎片的自动重建或重组

    [推荐]数据库索引碎片的自动重建或重组 [推荐]数据库索引碎片的自动重建或重组 --通过知识共享树立个人品牌.   数据库随着使用时间,若不进行相应管理就会越来越慢,优化数据库方法很多,在此不介绍,说 ...

  4. oracle建索引默认并发,ORACLE重建索引需要考虑问题

    一:考虑重建索引的场合 1:表上频繁发生update,delete操作 2:表上发生了alter table ..move操作(move操作导致了rowid变化) 二:判断重建索引的标准 索引重建是否 ...

  5. mysql为什么要重建索引_MySQL表索引为什么会遭破坏?

    此文章主要向大家描述的是MySQL表索引被破坏的问题的产生缘由,以及针对这一问题我们给出其具体的解决方案,下面的文章就是对其相关内容的具体介绍,希望在你今后的学习中会有所帮助. 下午上班,惊闻我的de ...

  6. mysql索引创建规则、联合与一般索引、执行计划、索引选择,索引重建与下推

    数据库索引怎么建,什么时候用到 索引优缺点:为主键外建where子句建立索引可以加速数据库查询,但是索引占用内存,同时update和insert的时候需要同步修改;索引的实现通常使用其变种B+树. 建 ...

  7. mysql repair 索引_mysql 创建索引、重建索引、查询索引、删除索引 转自:http://www.phpernote.com/mysql/942.html...

    本篇文章主要是对MySQL索引操作方法做了一下总结,包括创建索引.重建索引.查询索引.删除索引的操作.以下所列示例中中 `table_name` 表示数据表名,`index_name` 表示索引名,c ...

  8. 2.Lucene3.6.2包介绍,第一个Lucene案例介绍,查看索引信息的工具lukeall介绍,Luke查看的索引库内容,索引查找过程

     1  Lucen目录介绍 2  lucene-core-3.6.2.jar是lucene开发核心jar包 contrib  目录存放,包含一些扩展jar包 3  案例 建立第一个Lucene项目 ...

  9. 数据库元数据数据字典查询_4_列出给定表的索引信息

    列出给定表的索引信息 需求描述 需求:查询出给定的表emp的索引信息. 解决方法:通过各个数据库里提供的与索引相关的数据字典进行查询. 注: 数据库数据集SQL脚本详见如下链接地址 员工表结构和数据初 ...

最新文章

  1. 如何自学python数据分析-良心整理!学习Python数据分析的正确姿势
  2. day12装饰器进阶
  3. linux字符处理工具 新手教程
  4. 邮箱通知php,PHPMailer 发送邮件(含详细介绍及使用方法说明)
  5. ejb 2.1 jboss_JBoss AS 8中的Java EE 7和EJB 3.2支持
  6. 【Pytorch神经网络理论篇】 05 Module类的使用方法+参数Parameters类+定义训练模型的步骤与方法
  7. GooglePerformanceTools--tcmalloc
  8. 创建线程时,需要创建的内容
  9. ubuntu10.4的更新源因过期无法更新的解决方法
  10. 计算机字符代码表,计算机ASCII码对照表
  11. 爬虫入门之绘图matplotlib与词云(七)
  12. J2ME-CLDC/MIDP资源
  13. 论坛源码手机php,【校园社区APP】带后台完整社区论坛手机应用源码
  14. C语言bmp转JPEG不用库函数,C++图片格式转换:BMP转JPEG
  15. logout退出登录该用get方法还是post方法?
  16. localstorage,sessionstorage,cookie
  17. 面试时被问有没有别家offer,回答没有,面试总是挂!回答有,就说我是面试选手,欺骗公司!...
  18. 地铁中计算机网络专业,计算机网络技术在地铁AFC系统中的应用原稿(全文完整版)...
  19. 浅析安全启动(Secure Boot) —写得很好
  20. CenOs安装jdk

热门文章

  1. 解决AndroidStudio更新后在 Building gradle project info 一直卡住
  2. redhat7图形界面网卡设置_Redhat Linux Interprise基本网络配置与调试
  3. cdh 安装_使用Cloudera的CDH部署Hadoop:第二步,安装JDK
  4. 封装element分页组件
  5. android登录操作代码,Android Studio实现第三方QQ登录操作代码
  6. axios请求接口http_超级简单好用的 Vue封装axios
  7. python 中主线程结束 子线程还在运行么_Python爬虫进阶(二)爬虫之多任务模块(Ⅰ)...
  8. 姓名的首字母组成的图案C语言怎么编,c语言编写一个程序,根据用户输入英文名和姓先显示姓氏,其后跟一个逗号,然后显示名的首字母:...
  9. turtle库的学习
  10. Leetcode 581.最短无序连续子数组