SET NOCOUNT ON; SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
USE --< Enter user database name ;
DECLARE @compression_type sysname;
SELECT @compression_type = N'PAGE'; --<---- Valid values are: PAGE or ROW
IF OBJECT_ID('tempdb..#estimate_data_compression_savings') IS NOT NULL DROP TABLE #estimate_data_compression_savings; CREATE TABLE #estimate_data_compression_savings
(
Id int identity (1,1) PRIMARY KEY CLUSTERED NOT NULL
,[File_Group] sysname NULL
,[is_read_only] bit NULL
,[index_name] sysname NULL
,[type] tinyint NULL
,[data_compression_desc] sysname NULL
,[rows] bigint NULL
,[reserved_page_count] bigint NULL
,[reserved_MB] bigint NULL
,object_name sysname NOT NULL
,schema_name sysname NOT NULL
,index_id int NOT NULL
,partition_number int NOT NULL
,partition_count int NULL
,[size_with_current_compression_setting (KB)] bigint NOT NULL
,[size_with_requested_compression_setting (KB)] bigint NOT NULL
,[sample_size_with_current_compression_setting (KB)] bigint NOT NULL
,[sample_size_with_requested_compression_setting (KB)] bigint NOT NULL
,[command] varchar(8000) NULL
,[error] varchar(8000) NULL
);
IF OBJECT_ID('tempdb..#Data') IS NOT NULL DROP TABLE #Data; CREATE TABLE #Data
(
schemaname sysname
,tablename sysname
,objectid int
,indexname sysname
,indexid int
,[blob] bit
);
-- Get meta data for the rebuild process.
INSERT #Data (schemaname, tablename, objectid, indexname, indexid, blob)
SELECT
Derived.schemaname
,Derived.tablename
,Derived.tableid
,Derived.indexname
,Derived.indexid
,Derived.blob
FROM
(
-- Get clustered indexes information
SELECT
SCHEMA_NAME(Derived2.[schema_id]) AS schemaname
,Derived2.tablename AS tablename
,Derived2.[object_id] AS tableid
,i.name AS indexname
,i.index_id AS indexid
,Derived2.blob AS blob
FROM
(
SELECT
t.[object_id] AS [object_id]
,t.[name] AS tablename
,t.[schema_id] AS [schema_id]
,CASE WHEN EXISTS (SELECT 1 FROM sys.columns c WHERE c.object_id = t.object_id AND (system_type_id IN (35, 34, 241, 99) /* column type that doesn't support on-line index rebuild. (text,image,XML,ntext -> 35,34,241,99) */ OR max_length < 0) ) THEN 1 ELSE 0 END AS blob
FROM sys.tables t
)Derived2
INNER JOIN sys.indexes i ON Derived2.[object_id] = i.[object_id]
WHERE i.type = 1 /* clustered */
UNION
-- Get nonclustered index information
SELECT
SCHEMA_NAME(t.schema_id) AS schemaname
,t.Name AS [tablename]
,t.[object_id] AS tableid
,i.name AS [indexname]
,i.index_id AS indexid
,CASE WHEN EXISTS ( SELECT 1 FROM sys.index_columns ic INNER JOIN sys.columns c ON ic.[object_id] = c.[object_id] AND ic.column_id = c.column_id WHERE i.object_id = ic.object_id AND i.index_id = ic.index_id AND (c.system_type_id IN (35, 34, 241, 99) /* column type that doesn't support on-line index rebuild. (text,image,XML,ntext -> 35,34,241,99) */ OR c.max_length < 0) ) THEN 1 ELSE 0 END AS blob
FROM sys.tables t
INNER JOIN sys.indexes i ON t.[object_id] = i.[object_id]
WHERE i.type > 1 /* nonclustered */
)Derived
ORDER BY Derived.tablename;
DECLARE CUR CURSOR LOCAL FAST_FORWARD READ_ONLY FOR
SELECT DISTINCT
--TOP 2
fg.name AS [File_Group]
,fg.is_read_only
,s.[name] AS [schema_name]
--,o.[object_id]
,o.[name] AS [object_name]
,i.index_id
,i.[name] [index_name]
,i.[type]
,p.partition_number
,(SELECT COUNT(*) FROM sys.partitions part WHERE part.[object_id] = p.[object_id] AND part.[index_id] = p.[index_id]) AS partitions_count
,p.data_compression_desc
,p.[rows]
--,au.total_pages
--,ps.used_page_count
--,ps.row_count
,ps.reserved_page_count
,(ps.reserved_page_count * 8) / 1024 AS reserved_MB
,#Data.blob
,#Data.indexid
FROM sys.indexes i
INNER JOIN sys.objects o ON i.[object_id] = o.[object_id]
INNER JOIN sys.schemas s ON o.[schema_id] = s.[schema_id]
INNER JOIN sys.partitions p ON p.[object_id] = i.[object_id] AND p.index_id = i.index_id
INNER JOIN sys.allocation_units au ON p.hobt_id = au.container_id
INNER JOIN sys.filegroups fg ON fg.data_space_id = au.data_space_id
INNER JOIN sys.dm_db_partition_stats ps ON ps.partition_id = p.partition_id
INNER JOIN #Data ON #Data.tablename COLLATE DATABASE_DEFAULT = o.name AND #Data.schemaname COLLATE DATABASE_DEFAULT = s.name AND #Data.indexid = i.index_id
WHERE 1=1
AND fg.is_read_only = 0
AND p.[rows] > 0
AND (ps.reserved_page_count * 8) / 1024 > 500 /* MB */
/* Get the active partition */
AND
(
EXISTS(SELECT 1 FROM sys.partitions p_empty WHERE p.[object_id] = p_empty.[object_id] AND p.index_id = p_empty.index_id AND p.partition_number = p_empty.partition_number - 1 AND p_empty.[rows] = 0 )
OR
NOT EXISTS(SELECT 1 FROM sys.partitions p_empty2 WHERE p.[object_id] = p_empty2.[object_id] AND p.index_id = p_empty2.index_id AND p_empty2.partition_number = 2 )
)
ORDER BY o.[name] DESC;
OPEN CUR;
DECLARE @File_Group sysname, @is_read_only bit, @schema_name sysname, @object_name sysname, @index_id int, @index_name sysname, @type sysname
, @partition_number int, @data_compression_desc sysname, @rows int, @reserved_page_count int, @reserved_MB int, @partition_count int;
DECLARE @Ident int, @command varchar(8000), @error varchar(8000), @blob BIT, @indexid int;
FETCH NEXT FROM CUR INTO @File_Group, @is_read_only, @schema_name, @object_name,@index_id, @index_name, @type, @partition_number, @partition_count, @data_compression_desc, @rows, @reserved_page_count, @reserved_MB, @blob, @indexid ;
WHILE (@@FETCH_STATUS <> -1)
BEGIN;
BEGIN TRY
/* exec the procedure sp_estimate_data_compression_savings into a table */
INSERT dbo.#estimate_data_compression_savings
([object_name]
,[schema_name]
,[index_id]
,[partition_number]
,[size_with_current_compression_setting (KB)]
,[size_with_requested_compression_setting (KB)]
,[sample_size_with_current_compression_setting (KB)]
,[sample_size_with_requested_compression_setting (KB)])
EXEC sp_estimate_data_compression_savings
@schema_name = @schema_name
,@object_name = @object_name
,@index_id = @index_id
,@partition_number = @partition_number
,@data_compression = @compression_type;
SELECT @Ident = SCOPE_IDENTITY();
/*
SELECT @command = '
EXEC sp_estimate_data_compression_savings
@schema_name = ''' + @schema_name + '''
,@object_name = ''' + @object_name + '''
,@index_id = ' + CAST(@index_id AS varchar(20)) + '
,@partition_number = ' + CAST(@partition_number AS varchar(20)) + '
,@data_compression = ''' + @compression_type + ''';';
*/
/* If the table is not partitioned */
IF (@partition_count = 1)
BEGIN;
/* If the index is clustered and the table has a blob column it can only be rebuild offline */
IF (@indexid = 1 AND @blob = 1)
BEGIN;
SELECT @command = 'ALTER INDEX [' + @index_name + '] ON [' + @schema_name + '].[' + @object_name + '] REBUILD WITH (DATA_COMPRESSION = ' + @compression_type + ', ONLINE = OFF );';
END
/* All other cases; clustered index with no blob and noneclsutered indexes can be rebuild online */
ELSE IF (@indexid = 1 AND @blob = 0) OR (@indexid > 1)
BEGIN
SELECT @command = 'ALTER INDEX [' + @index_name + '] ON [' + @schema_name + '].[' + @object_name + '] REBUILD WITH (DATA_COMPRESSION = ' + @compression_type + ', ONLINE = ON );';
END;
END;
/* If the table is partitioned it can only be rebuild offline */
ELSE IF (@partition_count > 1)
BEGIN;
SELECT @command =
'ALTER INDEX [' + @index_name + '] ON [' + @schema_name + '].[' + @object_name + '] REBUILD PARTITION = ' + CAST(@partition_number AS varchar(20)) + ' WITH (DATA_COMPRESSION = ' + @compression_type + ', ONLINE = OFF );';
END;
PRINT @command;
/* update the table with additional info */
UPDATE dbo.#estimate_data_compression_savings SET
[File_Group] = @File_Group
,[is_read_only] = @is_read_only
,[index_name] = @index_name
,[type] = @type
,[data_compression_desc] = @data_compression_desc
,[rows] = @rows
,[reserved_page_count] = @reserved_page_count
,[reserved_MB] = @reserved_MB
,[command] = @command
,[partition_count] = @partition_count
WHERE Id = @Ident;
END TRY
BEGIN CATCH;
SELECT @error = ERROR_MESSAGE();
UPDATE dbo.#estimate_data_compression_savings SET
[File_Group] = @File_Group
,[is_read_only] = @is_read_only
,[index_name] = @index_name
,[type] = @type
,[data_compression_desc] = @data_compression_desc
,[rows] = @rows
,[reserved_page_count] = @reserved_page_count
,[reserved_MB] = @reserved_MB
,[command] = @command
,[partition_count] = @partition_count
,[error] = @error
WHERE Id = @Ident;
END CATCH;
SELECT @Ident = NULL, @error = NULL;
FETCH NEXT FROM CUR INTO @File_Group, @is_read_only, @schema_name, @object_name, @index_id, @index_name, @type, @partition_number, @partition_count, @data_compression_desc, @rows, @reserved_page_count, @reserved_MB, @blob, @indexid ;
END;
CLOSE CUR; DEALLOCATE CUR;
GO
/* Get the final results */
SELECT [Id]
,[File_Group]
,[is_read_only]
,[index_name]
,[type]
,[data_compression_desc]
,[rows]
,[reserved_page_count]
,[reserved_MB]
,[object_name]
,[schema_name]
,[index_id]
,[partition_number]
,[partition_count]
,[size_with_current_compression_setting (KB)] / 1024 AS [size_with_current_compression_setting (MB)]
,[size_with_requested_compression_setting (KB)] / 1024 AS [size_with_requested_compression_setting (MB)]
,([size_with_current_compression_setting (KB)] - [size_with_requested_compression_setting (KB)]) / 1024 AS diff_MB
,[sample_size_with_current_compression_setting (KB)] / 1024 AS [sample_size_with_current_compression_setting (MB)]
,[sample_size_with_requested_compression_setting (KB)] / 1024 AS [sample_size_with_requested_compression_setting (MB)]
,[command]
FROM dbo.#estimate_data_compression_savings WHERE 1=1
AND (
[size_with_requested_compression_setting (KB)] < [size_with_current_compression_setting (KB)]
OR [sample_size_with_requested_compression_setting (KB)] < [sample_size_with_current_compression_setting (KB)]
)
--AND File_Group = ''
ORDER BY ( [size_with_current_compression_setting (KB)] - [size_with_requested_compression_setting (KB)]) DESC;