当数据库表使用久了,特别是数据频繁增删改后,索引会产生碎片,会影响索引的效率,这就需要及时优化。
官方建议大于百分三十的索引是要重建的.
索引相关语句
---------------------------------------------重新组织索引----------------------------------------
ALTER INDEX IX_Employee_OrganizationalLevel_OrganizationalNode ON HumanResources.Employee
REORGANIZE ;
GO
--------------------------------------------重新组织表中所有的索引--------------------------------------------
ALTER INDEX ALL ON HumanResources.Employee
REORGANIZE
-------------------------------------------重新生成的索引--------------------------------------------
ALTER INDEX PK_Employee_BusinessEntityID ON HumanResources.Employee
REBUILD;
GO
---------------------------------------------重新生成表中所有的索引--------------------------------------------
ALTER INDEX ALL ON Production.Product
REBUILD WITH (FILLFACTOR = 80, SORT_IN_TEMPDB = ON,
STATISTICS_NORECOMPUTE = ON);
有关重新生成,组织索引的操作详见:
SQL Server 重新组织生成索引 - pursuer.chen
查看碎片大于30%的索引
select object_id= object_id,indexid = index_id,partitionnum = partition_number,frag= avg_fragmentation_in_percent
into #work_to_do
from sys.dm_db_index_physical_stats(db_id(), null, null , null, 'LIMITED') --dm_ph_stats join sys.dm_db_partition_stats dm_pa_st on dm_ph_stats.object_id=dm_pa_st.object_id
where avg_fragmentation_in_percent >= 30.0
and index_id > 0
and object_id in (select distinct a.object_id from sys.dm_db_partition_stats a join sys.indexes b
on a.object_id=b.object_id and a.index_id=b.index_id
where a.index_id>0
and a.in_row_data_page_count>1280 )
select a.object_id,a.name,a.type_desc,b.partitionnum ,b.frag,b.indexid from sys.indexes a , #work_to_do b
where a.object_id=b.object_id and a.index_id=b.indexid-- where object_id in(select objectid from #work_to_do)
drop table #work_to_do
批量重新组织或重新生成索引的语句
declare @NumLessthan30 int
declare @NumGreaterthan30_1 int
declare @NumGreaterthan30_2 int
set @NumLessthan30=0
set @NumGreaterthan30_1=0
set @NumGreaterthan30_2=0
SET NOCOUNT ON
DECLARE @Objectid INT, @Indexid INT,@schemaname VARCHAR(100),@tablename VARCHAR(300),@ixname VARCHAR(500),@avg_fip float,@command VARCHAR(4000)
DECLARE IX_Cursor CURSOR FOR
SELECT A.object_id,A.index_id,QUOTENAME(SS.NAME) AS schemaname,QUOTENAME(OBJECT_NAME(B.object_id,B.database_id))as tablename ,QUOTENAME(A.name) AS ixname,B.avg_fragmentation_in_percent AS avg_fip FROM sys.indexes A inner join sys.dm_db_index_physical_stats(DB_ID(),NULL,NULL,NULL,'LIMITED') AS B
ON A.object_id=B.object_id and A.index_id=B.index_id
INNER JOIN SYS.OBJECTS OS ON A.object_id=OS.object_id
INNER JOIN sys.schemas SS ON OS.schema_id=SS.schema_id
WHERE B.avg_fragmentation_in_percent>10 and B.page_count>20 AND A.index_id>0 AND A.IS_DISABLED<>1--AND OS.name='book'
ORDER BY tablename,ixname
OPEN IX_Cursor
FETCH NEXT FROM IX_Cursor INTO @Objectid,@Indexid,@schemaname,@tablename,@ixname,@avg_fip
WHILE @@FETCH_STATUS=0
BEGIN
IF @avg_fip<30.0
begin
SET @command=N'ALTER INDEX '+@ixname+N' ON '+@schemaname+N'.'+ @tablename+N' REORGANIZE ';
set @NumLessthan30=@NumLessthan30+1;
end
IF @avg_fip>=30.0 AND @Indexid=1
BEGIN
IF EXISTS (SELECT * FROM SYS.columns WHERE OBJECT_ID=@Objectid AND max_length in(-1,16))
SET @command=N'ALTER INDEX '+@ixname+N' ON '+@schemaname+N'.'+ @tablename+N' REBUILD ';
ELSE
SET @command=N'ALTER INDEX '+@ixname+N' ON '+@schemaname+N'.'+ @tablename+N' REBUILD '+N' WITH (ONLINE = ON)';
set @NumGreaterthan30_1=@NumGreaterthan30_1+1;
END
IF @avg_fip>=30.0 AND @Indexid>1
BEGIN
IF EXISTS (SELECT * FROM SYS.index_columns IC INNER JOIN SYS.columns CS ON CS.OBJECT_ID=IC.OBJECT_ID AND CS.column_id=IC.column_id WHERE IC.OBJECT_ID=@Objectid AND IC.index_id=@Indexid AND CS.max_length in(-1,16) )
SET @command=N'ALTER INDEX '+@ixname+N' ON '+@schemaname+N'.'+ @tablename+N' REBUILD ';
ELSE
SET @command=N'ALTER INDEX '+@ixname+N' ON '+@schemaname+N'.'+ @tablename+N' REBUILD '+N' WITH (ONLINE = ON)';
set @NumGreaterthan30_2=@NumGreaterthan30_2+1;
END
PRINT @command
--指定1秒后执行
--waitfor delay '0:0:1.00'
--EXEC(@command)
FETCH NEXT FROM IX_Cursor INTO @Objectid,@Indexid,@schemaname,@tablename,@ixname,@avg_fip
END
CLOSE IX_Cursor
DEALLOCATE IX_Cursor
print '@NumLessthan30='
print @NumLessthan30
print '@NumGreaterthan30_1='
print @NumGreaterthan30_1
print '@NumGreaterthan30_2='
print @NumGreaterthan30_2
可以根据需要修改
延时执行的语句补充
因为里面用到的延时执行,所以补充下该函数的用法
SQL有定时执行的语句WaitFor。
语法格式:waitfor {delay 'time'|time 'time'}
delay后面的时间是需要延迟多长时间后执行。
time后面的时间是指定何时执行,格式为'HH:MM:SS',不支持日期
例:
--指定10:00执行
Begin
waitfor time '10:00'
select * from tablename
end
--指定等待1小时后执行
begin
waitfor delay '1:00'
select * from tablename
end
--指定等待毫秒级别后执行
waitfor delay '0:0:0.01'
--指定等待1秒后执行
waitfor delay '0:0:1.00'