本文參考html
https://www.cnblogs.com/CareySon/archive/2011/12/22/2297568.htmlsql
https://www.jb51.net/softjc/126055.html數據庫
本文須要對「索引」和MSSQL中數據的「存儲方式」有必定了解。測試
軟件常常在使用一段時間事後會平白無故卡頓,這是由於在數據庫(MSSQL)頻繁的插入和更新的操做過程當中會產生分頁,在分頁的過程當中產生碎片致使的。因此,對於碎片須要定時的處理。基本上全部的辦法都是基於對索引的重建和整理,只是方式不一樣。ui
以上方式各有優缺點,下面存儲過程主要使用3,4spa
先看一個整理碎片的存儲過程,而後採用做業的方式定時執行。.net
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
下面直觀的看一下碎片產生的過程code
--建立測試表 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')
--而後作更新操做後,繼續查看頁存儲狀況。server
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
明顯的邏輯讀取減小了。從而提升了性能