Dear all,
I'm using this query for reindexing according fragmentation levels it run either REORGANIZE or REBUILD.
It runs properly.. till it find one index with LOB datatype and aborts everything:
An online operation cannot be performed for index 'I_175ITEMIDX' because the index contains column 'NOTES' of data type text, ntext, image or FILESTREAM. For a non-clustered index, the
column could be an include column of the index. For a clustered index, the column could be any column of the table. If DROP_EXISTING is used, the column could be part of a new or old index. The operation must be performed offline.
How can I improve the query for indentifying all those indexes with LOB datatypes and put the tail "ONLINE=OFF"?
DECLARE @preferredReplica int
set nocount on
SET @preferredReplica = (SELECT [master].sys.fn_hadr_backup_is_preferred_replica('MyDb'))
IF (@preferredReplica = 0)
BEGIN
declare @fragmentation as table (
database_name sysname, [schema_name] sysname, table_name sysname, index_name sysname
, avg_fragmentation_in_percent decimal (28,2), avg_page_space_used_in_percent decimal (28,2)
, page_count bigint, record_count bigint, fragment_count bigint
, recommendation nvarchar(4000)
)
declare @database_name sysname
declare @query nvarchar(max)
declare @min_frag_rebuild int
declare @min_frag_reorganize int
declare @min_fill_rebuild int
declare @min_fill_reorganize int
declare @min_size int
declare @maxdop int
/*********************************************************************************************************************/
set @min_frag_rebuild = 25 -- More than 25% of fragmentation --> Rebuild
set @min_frag_reorganize = 10 -- More than 10% of fragmentation --> Reorganize
set @min_fill_rebuild = 60 -- Minimum fill ratio to rebuild
set @min_fill_reorganize = 75 -- Minimum fill ratio to reorganize
set @min_size = 100 -- Minimum index size to maintain the index
set @maxdop = (select cpu_count from sys.dm_os_sys_info) /8 -- Number of processors to be used for the rebuild
/*********************************************************************************************************************/
IF (SELECT OBJECT_ID('tempdb..#db')) IS NOT NULL
DROP TABLE #db;
SELECT d1.[name] into #db
FROM sys.databases d1
where d1.state_desc = 'ONLINE' and is_read_only = 0
and database_id > 4 AND D1.NAME IN('MyDb')
DECLARE c_databases CURSOR read_only FOR
SELECT [name] FROM #db
OPEN c_databases
FETCH NEXT FROM c_databases
into @database_name
WHILE @@FETCH_STATUS = 0
BEGIN
set @query = N'
with dt as (
SELECT
index_id, object_id, database_id
, MAX(avg_fragmentation_in_percent) avg_fragmentation_in_percent, MAX(avg_page_space_used_in_percent) avg_page_space_used_in_percent
, MAX(page_count) page_count, MAX(record_count) record_count, MAX(fragment_count) fragment_count
from sys.dm_db_index_physical_stats (DB_ID('''+ @database_name +'''), NULL, NULL, NULL, NULL)
where ( avg_fragmentation_in_percent > ' + convert(char(3), @min_frag_reorganize) +'
or avg_page_space_used_in_percent < ' + convert(char(3), @min_fill_reorganize) + ')
and page_count > ' + convert(char(10), @min_size) + '
GROUP BY index_id, object_id, database_id
)
SELECT
db_name(database_id) database_name, s.name schema_name, t.name table_name, i.name index_name
, dt.avg_fragmentation_in_percent, dt.avg_page_space_used_in_percent, page_count, record_count, fragment_count
, case
when ( avg_page_space_used_in_percent < ' + convert(char(3),@min_fill_rebuild) +
' or avg_fragmentation_in_percent > ' + convert(char(3),@min_frag_rebuild) +
') then ''ALTER INDEX '' + QUOTENAME(i.name)+ '' ON '+ QUOTENAME(@database_name) + '.'' + QUOTENAME(s.name) +''.''+ QUOTENAME(t.name) +'' REBUILD ''
else ''ALTER INDEX '' + QUOTENAME(i.name)+ '' ON '+ QUOTENAME(@database_name) + '.'' + QUOTENAME(s.name) +''.''+ QUOTENAME(t.name) +'' REORGANIZE ''
end SENTENCIA_RECOMENDADA
FROM dt
INNER JOIN '+ QUOTENAME(@database_name) + '.sys.indexes i
ON dt.object_id = i.object_id and dt.index_id = i.index_id
INNER JOIN '+ QUOTENAME(@database_name) + '.sys.tables t
ON i.object_id = t.object_id
INNER JOIN '+ QUOTENAME(@database_name) + '.sys.schemas s
ON t.schema_id = s.schema_id
WHERE dt.index_id <> 0
ORDER BY database_name, s.name, t.name, i.name'
insert into @fragmentation (
database_name, [schema_name], table_name, index_name
, avg_fragmentation_in_percent, avg_page_space_used_in_percent
, page_count, record_count, fragment_count
, recommendation)
execute(@query)
FETCH NEXT FROM c_databases
into @database_name
END
CLOSE c_databases
DEALLOCATE c_databases
DROP TABLE #db
-- Get the fragmentation report
select * from @fragmentation
-- Defragment the indexes
if exists(select 1 from @fragmentation)
begin
DECLARE cursorBBDD_new CURSOR read_only fast_forward forward_only FOR
select database_name, [table_name], index_name, recommendation from @fragmentation
OPEN cursorBBDD_new
declare @databaseName sysname
declare @tableName nvarchar(100)
declare @Recommendation nvarchar(1024)
declare @Recommendation_new nvarchar (1024)
declare @indexname nvarchar(20)
FETCH NEXT FROM cursorBBDD_new
into @databaseName, @tableName, @indexname, @Recommendation
WHILE @@FETCH_STATUS = 0
BEGIN
-- Try to do it online and failback to offline mode if it is not possible
BEGIN TRY
IF (patindex('%REBUILD%',@Recommendation) <> 0 )
set @Recommendation_new='use ' + @databaseName + ';' + @Recommendation + 'WITH (ONLINE=ON, MAXDOP=' + CAST(@maxdop as varchar(10)) + ')'
ELSE
set @Recommendation_new='use ' + @databaseName + ';' + @Recommendation
exec (@recommendation_new)
print @Recommendation_new
END TRY
BEGIN CATCH
IF (patindex('%REBUILD%',@Recommendation) <> 0 )
set @Recommendation_new='use ' + @databaseName + ';' + @Recommendation + 'WITH (ONLINE=OFF, MAXDOP=' + CAST(@maxdop as varchar(10)) + ')'
ELSE
set @Recommendation_new='use ' + @databaseName + ';' + @Recommendation
-- Execute the command and then print it
exec (@recommendation_new)
print @Recommendation_new
END CATCH
FETCH NEXT FROM cursorBBDD_new
into @databaseName, @tableName, @indexname, @Recommendation
END
CLOSE cursorBBDD_new
DEALLOCATE cursorBBDD_new
end
end
This query give us info about datatypes:
select o.name objectname, i.name indexname, c.name as columnname, t.name, i.type_desc
from sys.objects o
join sys.indexes i on i.object_id = o.object_id
join sys.index_columns ic on ic.index_id = i.index_id and ic.object_id = i.object_id
join sys.columns c on c.object_id = o.object_id and c.column_id = ic.column_id
join sys.types t on c.system_type_id = t.system_type_id