本文参考
https://www.cnblogs.com/careyson/archive/2011/12/22/2297568.html
本文需要对“索引”和mssql中数据的“存储方式”有一定了解。
软件经常在使用一段时间过后会无缘无故卡顿,这是因为在数据库(mssql)频繁的插入和更新的操作过程中会产生分页,在分页的过程中产生碎片导致的。所以,对于碎片需要定时的处理。基本上所有的办法都是基于对索引的重建和整理,只是方式不同。
- 删除索引并重建
- 使用drop_existing语句重建索引
- 使用alter index rebuild语句重建索引
- 使用alter index reorganize
以上方式各有优缺点,下面存储过程主要使用3,4
先看一个整理碎片的存储过程,然后采用作业的方式定时执行。
create procedure [dbo].[proc_rebuild_index] @ret int output as set nocount on begin declare @flddefragfragment int = 10; declare @fldrebuildfragment int = 30; declare @fldminpagecount int = 1000; declare @fldtable varchar(256); declare @fldindex varchar(256); declare @fldpercent int; declare @sql varchar(256); declare @dbid int; begin try set @ret = -1; set @dbid = db_id(); -- 获取索引碎片状况 declare curindex cursor local static read_only forward_only for select tbl.name table_name ,idx.name index_name ,avgp.avg_fragmentation_in_percent from sys.dm_db_index_physical_stats(@dbid, null,null, null, 'limited') as avgp inner join sys.indexes as idx on avgp.object_id = idx.object_id and avgp.index_id = idx.index_id inner join sys.tables as tbl on avgp.object_id = tbl.object_id inner join sys.dm_db_partition_stats ps on avgp.object_id = ps.object_id and avgp.index_id = ps.index_id where avgp.index_id >= 1 and avgp.avg_fragmentation_in_percent >= @flddefragfragment and ps.reserved_page_count >= @fldminpagecount; -- 打开游标 open curindex; -- 获取游标 fetch next from curindex into @fldtable,@fldindex,@fldpercent; while @@fetch_status = 0 begin --碎片率大于30,重建索引 if @fldpercent >= @fldrebuildfragment begin set @sql = 'alter index ' + @fldindex + ' on ' + @fldtable + ' rebuild'; exec(@sql); end else --碎片率小于30,重组索引 begin set @sql = 'alter index ' + @fldindex + ' on ' + @fldtable + ' reorganize'; exec(@sql); end -- 获取游标 fetch next from curindex into @fldtable,@fldindex,@fldpercent; end -- 关闭游标 close curindex; deallocate curindex; set @ret = 0; end try begin catch set @ret = -1; declare @errormessage nvarchar(4000); declare @errorseverity int; declare @errorstate int; select @errormessage = error_message() , @errorseverity = error_severity() , @errorstate = error_state(); raiserror( @errormessage, @errorseverity, @errorstate); return; end catch; end
下面直观的看一下碎片产生的过程
--创建测试表 if object_id('test') is not null drop table test go create table test ( col1 int, col2 char(985), col3 varchar(10) ) go --创建聚焦索引 create clustered index cix on test(col1); go --插入数据 declare @var int set @var=100 while (@var<900) begin insert into test(col1, col2, col3) values (@var, 'xxx', '') set @var=@var+100 end; --查看页存储情况 select page_count, avg_page_space_used_in_percent, record_count, avg_record_size_in_bytes, avg_fragmentation_in_percent, fragment_count, * from [master].sys.dm_db_index_physical_stats(db_id(), object_id('test'), null, null, 'sampled')
–然后做更新操作后,继续查看页存储情况。
update test set col3='更新测试' where col1=100
--再次插入数据后查看页存储情况 declare @var int set @var=100 while (@var<900) begin insert into test(col1, col2, col3) values (@var, '插入测试', '') set @var=@var+100 end;
--下面看下对碎片整理之前和之后的io set statistics io on select * from test alter index cix on test rebuild select * from test set statistics io off
明显的逻辑读取减少了。从而提高了性能