Suggest Compression Strategies for Tables and Indexes
I make no secret of the fact that I think that table compression was the best thing added to SQL Server 2008.
It seems like every week that I’m talking to clients about it. They have Enterprise Edition but they weren’t using it because they were familiar with O/S level disk compression and they think that compression will mean smaller and slower, yet this often couldn’t be further from the truth for customers whose databases are currently I/O bound or who don’t have enough memory in their buffer cache for it to work correctly.
It’s important though, to make sure the correct form of compression is used for each table and index. In fact, the decision should be taken for each partition of each table and index if the table is partitioned. We often recommend different compression strategies for different partitions of the same table.
To make it easier to decide which form of compression might suit, I’ve created another version of the script that I use as a first pass in determining compression strategies. The earlier version suggested ROW and/or PAGE compression. While this version can do the same, it also considers the clustered columnstore indexes that are part of the Enterprise Edition of SQL Server 2014. (I’ve included a switch to turn that function on or off in case you don’t have 2014 yet).
The cutoff points are configurable but my default values are as shown.
It is important that this script only be run after the system has been in use for long enough to have experienced typical usage patterns.
- CCI (Clustered Columnstore Index) will be recommended where the partition is scanned more than 95% of the time, updated less than 10% of the time, seeks and lookups are less than 5% of the time, and where there are at least 800,000 rows. It will also only be recommended if it is supported.
- PAGE will be recommended where the partition is scanned more than 75% of the time and updated less than 20% of the time.
- ROW will be recommended in all other cases. We believe that ROW should be the default in SQL Server across the board, instead of NONE.
I hope this helps you to get into using compression where it makes sense for you.
------------------------------------------------------------------------------- Suggest data compression changes for tables and indexes---- Dr Greg Low-- March 2015-------------------------------------------------------------------------------DECLARE @ClusteredColumnstoreScansCutoff int = 95;DECLARE @ClusteredColumnstoreUpdatesCutoff int = 10;DECLARE @ClusteredColumnstoreSeeksLookupsCutoff int = 5;DECLARE @ClusteredColumnstoreTotalRowsCutoff bigint = 800000;DECLARE @PageCompressionScansCutoff int = 75;DECLARE @PageCompressionUpdatesCutoff int = 20;DECLARE @IsClusteredColumnstoreSupported bit = 1;-----------------------------------------------------------------------------WITH IndexUsageStatsAS( SELECT object_id AS ObjectID,index_id AS IndexID,COALESCE(user_seeks, 0) + COALESCE(system_seeks, 0) AS Seeks,COALESCE(user_scans, 0) + COALESCE(system_scans, 0) AS Scans,COALESCE(user_lookups, 0) + COALESCE(system_lookups, 0) AS Lookups,COALESCE(user_updates, 0) + COALESCE(system_updates, 0) AS Updates,COALESCE(user_seeks, 0) + COALESCE(system_seeks, 0)+ COALESCE(user_scans, 0) + COALESCE(system_scans, 0)+ COALESCE(user_lookups, 0) + COALESCE(system_lookups, 0)+ COALESCE(user_updates, 0) + COALESCE(system_updates, 0) AS OperationsFROM sys.dm_db_index_usage_statsWHERE database_id = DB_ID()),PartitionUsageDetailsAS( SELECT SCHEMA_NAME(t.schema_id) AS SchemaName,t.name AS TableName,i.name AS IndexName,i.index_id AS IndexID,i.type_desc AS IndexType,CASE WHEN COALESCE(Operations, 0) <> 0THEN CAST((COALESCE(Seeks, 0) + COALESCE(Lookups, 0)) * 100.0/ COALESCE(Operations, 0) AS int)ELSE 0END AS SeekLookupPercentage,CASE WHEN COALESCE(Operations, 0) <> 0THEN CAST(COALESCE(Scans, 0) * 100.0 / COALESCE(Operations, 0) AS int)ELSE 0END AS ScanPercentage,CASE WHEN COALeSCE(Operations, 0) <> 0THEN CAST(COALESCE(Updates, 0) * 100.0 / COALESCE(Operations, 0) AS int)ELSE 0END AS UpdatePercentage,p.partition_number AS PartitionNumber,p.data_compression_desc AS CurrentCompression,p.rows AS TotalRowsFROM sys.tables AS tINNER JOIN sys.indexes AS iON t.object_id = i.object_idINNER JOIN sys.partitions AS pON i.object_id = p.object_idAND i.index_id = p.index_idLEFT OUTER JOIN IndexUsageStats AS iusON i.object_id = ius.ObjectIDAND i.index_id = ius.IndexIDWHERE i.index_id > 0AND t.is_ms_shipped = 0AND t.type = N'U'),SuggestedPartitionCompressionTypesAS( SELECT pud.*,CASE WHEN pud.ScanPercentage >= @ClusteredColumnstoreScansCutoffAND pud.UpdatePercentage <= @ClusteredColumnstoreUpdatesCutoffAND pud.SeekLookupPercentage <= @ClusteredColumnstoreSeeksLookupsCutoffAND pud.TotalRows >= @ClusteredColumnstoreTotalRowsCutoffAND @IsClusteredColumnstoreSupported <> 0THEN N'CCI'WHEN pud.ScanPercentage >= @PageCompressionScansCutoffAND pud.UpdatePercentage <= @PageCompressionUpdatesCutoffTHEN N'PAGE'ELSE N'ROW'END AS SuggestedCompressionFROM PartitionUsageDetails AS pud)SELECT spct.SchemaName,spct.TableName,spct.IndexName,spct.PartitionNumber,spct.CurrentCompression,spct.SuggestedCompressionFROM SuggestedPartitionCompressionTypes AS spctWHERE spct.SuggestedCompression <> spct.CurrentCompressionORDER BY spct.SchemaName,spct.TableName,CASE WHEN spct.IndexID = 1 THEN 0 ELSE 1 END,spct.IndexName;
Saturday, March 7, 2015
The Bit Bucket (Greg Low): IDisposable : Suggest Compression Strategies for Tables and Indexes
Subscribe to:
Post Comments
(
Atom
)
No comments :
Post a Comment