SQL procka pro rebuild či reorganizaci indexů tabulky v db schématu.
Pokud je potřeba dělat automatický maintenance sql indexů, tak je zbytečné to dělat ručně. Zejména pokud se jedná o jednoúčelové, jednoduché tabulky kde není žádná chytristika.
Zatím se mi procka osvědčila a nikdo si nestěžoval :-).

Procku pouštím periodicky z ADF pro většinu indexů. A v rámci datového zpracování pro tabulky/indexy kde bývá “těžší” provoz.

/****** Object:  StoredProcedure [dbo].[pIndexOptimalization]    Script Date: 05.05.2022 14:45:20 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
/*
+==============================================================================+
CREATED BY: martin.misar			DATE: 2021-11-02

DESCRIPTION: rebuil or reorganize for indexes which are too much fragmented
@pSchemaName - name of schema which will be opt
@pTableName
- if is null then all indexes in all tables in schema will be optimized
- if is set then all indexes for specified table will be optimized
@pReorganize - 1 = reorganize, 0 = do nothing 
@pRebuild - 1 = rebuild, 0 = do nothing 
@pDebug - 1 = only print sql statements, 0 = all will be executed

USAGE: ADF, ADB, SQL

EXAMPLE: EXEC [dbo].[pIndexOptimalization] N'schema', N'table',1,1,0

MODIFIED BY:						DATE:
	GOAL:
+==============================================================================+
*/
ALTER PROCEDURE [dbo].[pIndexOptimalization] (
	@pSchemaName varchar(200)
	,@pTableName varchar(200)
	,@pReorganize bit = 1
	,@pRebuild bit = 1
	,@pDebug bit = 0
)
AS
BEGIN

SET NOCOUNT ON;
DECLARE 
	@vTempVar1 NVARCHAR(max)	
	,@vStatement NVARCHAR(max)
	,@pDatabaseName varchar(100) = DB_NAME();

/* ----------------------------------------------------------------------------*/
drop table if exists #IndexTables;
drop table if exists #IndexBase;
/* ----------------------------------------------------------------------------*/
create table #IndexBase
(
	DatabaseName varchar(100),
	SchemaName varchar(100),
	TableName varchar(100),
	IndexName varchar(200),
	IndexId int,
	ObjectId int,
	AvgFrag decimal(18,2),
	ReorganizeIndex bit,
	RebuildIndex bit
)
/* ----------------------------------------------------------------------------*/
SELECT
	[TableName] = tabl.name
into 
	#IndexTables
FROM
	sys.schemas sche
	left join sys.tables tabl 
		on tabl.schema_id = sche.schema_id	
WHERE
	1=1
	and tabl.name is not null
	and sche.name = @pSchemaName
	and tabl.name = isnull( @pTableName, tabl.name)
/* ----------------------------------------------------------------------------*/
DECLARE IndexBase_cursor CURSOR
LOCAL FAST_FORWARD
FOR
	select TableName from #IndexTables 
OPEN IndexBase_cursor
FETCH NEXT FROM IndexBase_cursor into @vTempVar1
WHILE @@FETCH_STATUS = 0
BEGIN
	
	SELECT @vStatement =  'insert into #IndexBase select '+char(39)+@pDatabaseName+char(39)+','+char(39)+@pSchemaName+char(39)+','+char(39)+@vTempVar1+char(39)+', ind.name,ips.index_id,ips.object_id,ips.avg_fragmentation_in_percent, 
	case
		when avg_fragmentation_in_percent > 5 and avg_fragmentation_in_percent < 30 then 1
	else
		0
	end,
	case 
		when avg_fragmentation_in_percent >= 30 then 1
	else
		0
	end
	from 
		sys.dm_db_index_physical_stats(DB_ID(' +char(39)+ @pDatabaseName +char(39)+ '), OBJECT_ID('+char(39)+ @pDatabaseName + '.'+@pSchemaName+'.'+@vTempVar1+char(39)+'), NULL, NULL , ' + char(39) +'LIMITED' + char(39)+') ips
		left join sys.indexes ind 
			on ind.index_id = ips.index_id and ind.object_id = ips.object_id
	where 
		ind.name is not null'	;  
		
	if @pDebug = 1 Print @vStatement;
	EXEC sp_executesql @vStatement;

FETCH NEXT FROM IndexBase_cursor into @vTempVar1
END
CLOSE IndexBase_cursor
DEALLOCATE IndexBase_cursor
/* ----------------------------------------------------------------------------*/
-- INDEX REORGANIZE --
/* ----------------------------------------------------------------------------*/
if @pReorganize = 1
begin
	DECLARE IndexReorganize_cursor CURSOR
	LOCAL FAST_FORWARD
	FOR
		select 'ALTER INDEX ' + IndexName + ' ON ' + SchemaName + '.' + TableName + ' REORGANIZE' from #IndexBase where ReorganizeIndex = 1
	OPEN IndexReorganize_cursor
	FETCH NEXT FROM IndexReorganize_cursor into @vTempVar1
	WHILE @@FETCH_STATUS = 0
	BEGIN
	
		if @pDebug = 1 Print @vTempVar1;
		if @pDebug = 0 EXEC sp_executesql @vTempVar1;

	FETCH NEXT FROM IndexReorganize_cursor into @vTempVar1
	END
	CLOSE IndexReorganize_cursor
	DEALLOCATE IndexReorganize_cursor
end
/* ----------------------------------------------------------------------------*/
-- INDEX REBUILD
/* ----------------------------------------------------------------------------*/
if @pRebuild = 1
begin
	DECLARE IndexRebuild_cursor CURSOR
	LOCAL FAST_FORWARD
	FOR
		select 'ALTER INDEX ' + IndexName + ' ON ' + SchemaName + '.' + TableName + ' REBUILD WITH (FILLFACTOR = 80, SORT_IN_TEMPDB = ON, STATISTICS_NORECOMPUTE = ON,ONLINE = ON)' from #IndexBase where RebuildIndex = 1
	OPEN IndexRebuild_cursor
	FETCH NEXT FROM IndexRebuild_cursor into @vTempVar1
	WHILE @@FETCH_STATUS = 0
	BEGIN
	
		if @pDebug = 1 Print @vTempVar1;
		if @pDebug = 0 EXEC sp_executesql @vTempVar1;

	FETCH NEXT FROM IndexRebuild_cursor into @vTempVar1
	END
	CLOSE IndexRebuild_cursor
	DEALLOCATE IndexRebuild_cursor
end
/* ----------------------------------------------------------------------------*/
select * from #IndexBase;
return 1;
/* ----------------------------------------------------------------------------*/
drop table if exists #IndexTables;
drop table if exists #IndexBase;
/* ----------------------------------------------------------------------------*/
END