0% found this document useful (0 votes)
8 views2 pages

Identify Identity Columns Nearing The Maximum Threshold

The document outlines a SQL script for identifying 'identity' columns nearing their maximum threshold across multiple SQL Server databases. It details the use of various system views and functions to gather statistics about these columns, including handling cases with NULL values and zero rows. Additionally, it emphasizes the need for adequate permissions and provides a link to a blog post for further insights on addressing identity problems.

Uploaded by

Rofiq Ahmed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views2 pages

Identify Identity Columns Nearing The Maximum Threshold

The document outlines a SQL script for identifying 'identity' columns nearing their maximum threshold across multiple SQL Server databases. It details the use of various system views and functions to gather statistics about these columns, including handling cases with NULL values and zero rows. Additionally, it emphasizes the need for adequate permissions and provides a link to a blog post for further insights on addressing identity problems.

Uploaded by

Rofiq Ahmed
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 2

1 -- Identify "identity" columns nearing the maximum threshold

2
3 --Points to note:
4 --Observe the output columns [sample%], modCtr.
5 --I use these to decide if I "trust" the current statistics. If I don't, I run the
generated [UpdateStats] command.
6
7 --Observe the JOIN to sys.columns ON ISNULL(ic.column_id, sc.column_id.
8 --With multi-column indexes, it is quite rare for sys.stats_columns.stats_column_id
to not match sys.index_columns.key_ordinal.
9 --Unfortunately I have observed this mis-match in a few tables across the 4,000+
databases I manage.
10 --I have no idea what causes it and was unsuccessful in reproducing the issue.
11 --Bottom line, for indexed columns I use sys.index_columns.column_id where
key_ordinal = 1, to join to sys.columns.
12
13 --For columns having a NULL value in every row, sys.dm_db_stats_histogram returns
zero rows; DBCC SHOW_STATISTICS returns one row.
14 --For tables with zero rows, sys.dm_db_stats_properties and sys.dm_db_stats_histogram
return zero rows.
15
16 --I use CMS to execute the script across the entire fleet of 200+ SQL Server
instances,
17 --using sys.fn_hadr_is_primary_replica() to target databases on Primary replicas
only.
18 --For Azure SQL DB, execute the SELECT part of the script, replacing two single
quotes ('') with one (').
19
20 --Naturally, you need adequate permissions to execute the functions and DMVs used
within the script.
21
22 --Addressing the Identity problem: This blog post, I stumbled across, has some ideas.
23 --https://medium.com/@distillerytech/make-more-room-how-to-resolve-database-record-lim
itations-146035f3492e
24
25 --Query: Identify "identity" columns nearing the max threshold, across all databases
26 SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
27
28 drop table IF EXISTS #dbStats
29 GO
30 CREATE TABLE #dbStats (
31 [Database] [sysname] NOT NULL,
32 [Table] [sysname] NULL,
33 [Column] [sysname] NULL,
34 [Statistic] [sysname] NULL,
35 [Cardinality] BIGINT NULL,
36 [sample%] NUMERIC(5,2) NULL,
37 [modCtr] [bigint] NULL,
38 [lastStatsUpdate] DATETIME2(3) NULL,
39 [dataType] [sysname] NULL,
40 [max_length] [smallint] NULL,
41 [maxValue] [sql_variant] NULL,
42 [distinctValues] [bigint] NULL,
43 [max%] NUMERIC(7,4) NULL
44 )
45 GO
46
47 DECLARE @command varchar(4096)
48 SELECT @command = 'IF ''?'' NOT IN (''master'', ''model'', ''msdb'', ''tempdb'')
49 BEGIN
50 USE [?];
51 declare @isPrimary BIT = ISNULL(sys.fn_hadr_is_primary_replica (db_name()), 1)
52 -- ,@msg varchar(128) = db_name()+ '' at '' + convert(varchar(24), getdate(),
121);
53 --RAISERROR(@msg, 0, 1) WITH NOWAIT
54
55 INSERT INTO #dbStats
56 select [database]=DB_NAME(),
[table]=object_schema_name(ss.object_id)+''.''+object_name(ss.object_id)
57 ,c.name as columnName, ss.name as [Statistic]
58 ,CAST(OBJECTPROPERTYEX(ss.object_id, ''Cardinality'') AS BIGINT) AS Cardinality
59 ,[sample%]=cast(sp.rows_sampled*100./sp.rows as NUMERIC(5,2))
,modCtr=sp.modification_counter, CAST(sp.last_updated AS DATETIME2(3)) as
lastStatsUpdate
60 ,TYPE_NAME(c.user_type_id) AS [dataType], c.max_length
61 ,ssh.maxValue ,ssh.distinctValues
62 ,CAST(CAST(maxValue AS BIGINT)*(100.0/CASE max_length WHEN 1 THEN 255 WHEN 2 THEN
32767 WHEN 4 THEN 2147483647 WHEN 8 THEN 9223372036854775807 END) AS NUMERIC(7,4)) as
[max%]
63 FROM sys.stats ss
64 CROSS APPLY sys.dm_db_stats_properties(ss.object_id, ss.stats_id) AS sp
65 INNER JOIN sys.stats_columns sc ON sc.object_id = ss.object_id AND sc.stats_id =
ss.stats_id and sc.stats_column_id = 1 -- For indexes, the 1st column only
66 LEFT JOIN (sys.indexes i
67 INNER JOIN sys.index_columns ic on ic.object_id = i.object_id AND ic.index_id =
i.index_id and ic.key_ordinal = 1 -- For indexes, the 1st column only
68 ) on i.object_id = ss.object_id AND i.index_id = ss.stats_id
69 INNER JOIN sys.columns c ON c.object_id = sc.object_id AND c.column_id =
ISNULL(ic.column_id, sc.column_id) -- where stats_column_id does not match index
key_ordinal, histogram is built on the 1st index column
70 and c.is_identity = 1
71 OUTER APPLY (select maxValue=MAX(sh.range_high_key),
distinctValues=(COUNT(*)+SUM(sh.distinct_range_rows))
72 from sys.dm_db_stats_histogram(ss.object_id, ss.stats_id) sh
73 ) ssh
74 WHERE OBJECTPROPERTY(ss.object_id, ''IsMSShipped'') = 0
75 AND @isPrimary = 1
76 END'
77
78 EXEC sp_MSforeachdb @command
79
80 select *
81 ,UpdateStats = 'UPDATE STATISTICS '+[Table]+' '+QUOTENAME([Statistic])+' WITH
FULLSCAN; -- ,PERSIST_SAMPLE_PERCENT=ON; --'+[Column]
82 from #dbStats
83 --WHERE [max%] > 75 --< Uncomment & EDIT as you see fit
84 order by [database], maxValue
85
86 /*
87
88 Data Profiling examples you can explore:
89 distinctValues=(COUNT(*)+SUM(distinct_range_rows))
90 ,maxValue=MAX(range_high_key)
91 ,minValue=MIN(range_high_key)
92 ,[nulls]=MAX(IIF(range_high_key IS NULL, equal_rows, 0))
93 ,[empty]=MAX(IIF(range_high_key='', equal_rows, 0))
94 ,[zeros]=MAX(IIF(range_high_key=0, equal_rows, 0))
95 */

You might also like