Metrics install automatically if you have Redgate Monitor installed.
If you are using Redgate’s SQL Server monitoring tool, Redgate Monitor, you can instantly install and run this metric on your servers.
This metric returns the number of ascending statistics per database. A common problem relating to distribution statistics is associated with “ascending value columns” in a table. This generally happens when a large table has ascending values, and the most recent rows are the ones most commonly being accessed. When data values in a column ascend, most new insertions are beyond the range covered by the distribution statistics. This can lead to poorly performing plans.
Use this metric if you want to monitor the columns marked as ascending. After finding these columns, look at the queries on those tables to make sure you are getting an optimized plan for the query.
For more information, see http://www.simple-talk.com/sql/database-administration/statistics-on-ascending-columns/
The following query can be used to help you analyze which statistics are “branded” as ascending:
[sql]DBCC TRACEON(2388) WITH NO_INFOMSGS
SET NOCOUNT ON
IF OBJECT_ID(‘tempdb.dbo.#TMP_stats’) IS NOT NULL
DROP TABLE #TMP_stats
IF OBJECT_ID(‘tempdb.dbo.#TMP’) IS NOT NULL
DROP TABLE #TMP
CREATE TABLE #TMP(ROWID Int IDENTITY(1,1) PRIMARY KEY,
TableName NVarChar(800),
StatsName NVarChar(800),
"Updated" NVarChar(800),
"Table Cardinality" BigInt,
"Snapshot Ctr" BigInt,
"Steps" BigInt,
"Density" Float,
"Rows Above" Float,
"Rows Below" Float,
"Squared Variance Error" Float,
"Inserts Since Last Update" Float,
"Deletes Since Last Update" Float,
"Leading column Type" NVarChar(200))
;with CTE_1
as
(
select object_schema_name(a.object_id) schemaname,
object_name(a.object_id) as ‘TableName’,
a.name as ‘StatsName’,
stats_date(a.object_id, stats_id) as stats_last_updated_time,
(SELECT SUM(p.rows)
FROM sys.partitions p
WHERE a.object_id = p.object_id
and index_id <= 1) as number_of_rows
from sys.stats as a
inner join sys.objects as b
on a.object_id = b.object_id
where b.type = ‘U’
)
select IDENTITY(Int , 1,1) ROWID, *, ‘DBCC SHOW_STATISTICS ("’ + schemaname + ‘.’ + tablename + ‘",’ + statsname + ‘) WITH NO_INFOMSGS’ AS SQL
INTO #TMP_stats
from CTE_1
where number_of_rows > 1000
CREATE CLUSTERED INDEX ix ON #TMP_stats(ROWID)
DECLARE @SQL NVarChar(MAX),
@TableName NVarChar(800),
@StatsName NVarChar(800),
@ROWID Int,
@LastID Int,
@MaxID Int
SELECT @ROWID = 0,
@SQL = ”,
@TableName = ”,
@StatsName = ”,
@LastID = 0,
@MaxID = 2147483647
SELECT TOP 1
@ROWID = ROWID,
@SQL = SQL,
@TableName = TableName,
@StatsName = StatsName
FROM #TMP_stats
WHERE ROWID > @ROWID
ORDER BY ROWID
WHILE @@ROWCOUNT > 0
BEGIN
PRINT @SQL
INSERT INTO #TMP ("Updated","Table Cardinality","Snapshot Ctr","Steps","Density","Rows Above","Rows Below","Squared Variance Error","Inserts Since Last Update","Deletes Since Last Update","Leading column Type")
EXEC (@SQL)
SELECT @LastID = MIN(ROWID), @MaxID = MAX(ROWID)
FROM #TMP
WHERE ROWID BETWEEN (SELECT MIN(a.ROWID) FROM #TMP a WHERE a.TableName IS NULL) AND (SELECT MAX(b.ROWID) FROM #TMP b WHERE b.TableName IS NULL)
UPDATE #TMP SET TableName = @TableName, StatsName = @StatsName
WHERE ROWID BETWEEN @LastID AND @MaxID
SELECT TOP 1
@ROWID = ROWID,
@SQL = SQL,
@TableName = TableName,
@StatsName = StatsName
FROM #TMP_stats
WHERE ROWID > @ROWID
ORDER BY ROWID
END
DBCC TRACEOFF(2388) WITH NO_INFOMSGS
SELECT TableName,
StatsName,
(SELECT SUM(p.rows)
FROM sys.partitions p
WHERE OBJECT_ID(TableName) = p.object_id
AND index_id <= 1) as number_of_rows
FROM #TMP
WHERE "Leading column Type" = ‘Ascending’
ORDER BY number_of_rows DESC[/sql]
Note: The T-SQL query for this metric runs the DBCC TRACEON, command and you’ll need a sysadmin privilege to run this hint. It also uses undocumented features that may not be supported by future service packs or SQL Server version.
Metric definition
Name
Number of ascending statistics
Description
This metric returns the number of ascending statistics per database. A common problem relating to distribution statistics is associated with “ascending value columns” in a table. This generally happens when a large table has ascending values, and the most recent rows are the ones most commonly being accessed. When data values in a column ascend, most new insertions are beyond the range covered by the distribution statistics. This can lead to poorly performing plans.
Use this metric if you want to monitor the columns marked as ascending. After finding these columns, look at the queries on those tables to make sure you are getting an optimized plan for the query.
For more information, see http://www.simple-talk.com/sql/database-administration/statistics-on-ascending-columns/
The following query can be used to help you analyze which statistics are “branded” as ascending:
DBCC TRACEON(2388) WITH NO_INFOMSGS SET NOCOUNT ON IF OBJECT_ID('tempdb.dbo.#TMP_stats') IS NOT NULL DROP TABLE #TMP_stats IF OBJECT_ID('tempdb.dbo.#TMP') IS NOT NULL DROP TABLE #TMP CREATE TABLE #TMP ( ROWID INT IDENTITY(1, 1) PRIMARY KEY, TableName NVARCHAR(800), StatsName NVARCHAR(800), "Updated" NVARCHAR(800), "Table Cardinality" BIGINT, "Snapshot Ctr" BIGINT, "Steps" BIGINT, "Density" FLOAT, "Rows Above" FLOAT, "Rows Below" FLOAT, "Squared Variance Error" FLOAT, "Inserts Since Last Update" FLOAT, "Deletes Since Last Update" FLOAT, "Leading column Type" NVARCHAR(200) ); WITH CTE_1 AS (SELECT OBJECT_SCHEMA_NAME(a.object_id) schemaname, OBJECT_NAME(a.object_id) AS 'TableName', a.name AS 'StatsName', STATS_DATE(a.object_id, stats_id) AS stats_last_updated_time, (SELECT SUM(p.rows) FROM sys.partitions p WHERE a.object_id = p.object_id AND index_id <= 1 ) AS number_of_rows FROM sys.stats AS a INNER JOIN sys.objects AS b ON a.object_id = b.object_id WHERE b.type = 'U' ) SELECT IDENTITY( INT , 1,1 ) ROWID, *, 'DBCC SHOW_STATISTICS ("' + schemaname + '.' + tablename + '",' + statsname + ') WITH NO_INFOMSGS' AS SQL INTO #TMP_stats FROM CTE_1 WHERE number_of_rows > 1000 CREATE CLUSTERED INDEX ix ON #TMP_stats(ROWID) DECLARE @SQL NVARCHAR(MAX), @TableName NVARCHAR(800), @StatsName NVARCHAR(800), @ROWID INT, @LastID INT, @MaxID INT SELECT @ROWID = 0, @SQL = '', @TableName = '', @StatsName = '', @LastID = 0, @MaxID = 2147483647 SELECT TOP 1 @ROWID = ROWID, @SQL = SQL, @TableName = TableName, @StatsName = StatsName FROM #TMP_stats WHERE ROWID > @ROWID ORDER BY ROWID WHILE @@ROWCOUNT > 0 BEGIN PRINT @SQL INSERT INTO #TMP ("Updated", "Table Cardinality", "Snapshot Ctr", "Steps", "Density", "Rows Above", "Rows Below", "Squared Variance Error", "Inserts Since Last Update", "Deletes Since Last Update", "Leading column Type") EXEC (@SQL) SELECT @LastID = MIN(ROWID), @MaxID = MAX(ROWID) FROM #TMP WHERE ROWID BETWEEN (SELECT MIN(a.ROWID) FROM #TMP a WHERE a.TableName IS NULL ) AND (SELECT MAX(b.ROWID) FROM #TMP b WHERE b.TableName IS NULL ) UPDATE #TMP SET TableName = @TableName, StatsName = @StatsName WHERE ROWID BETWEEN @LastID AND @MaxID SELECT TOP 1 @ROWID = ROWID, @SQL = SQL, @TableName = TableName, @StatsName = StatsName FROM #TMP_stats WHERE ROWID > @ROWID ORDER BY ROWID END DBCC TRACEOFF(2388) WITH NO_INFOMSGS SELECT TableName, StatsName, (SELECT SUM(p.rows) FROM sys.partitions p WHERE OBJECT_ID(TableName) = p.object_id AND index_id <= 1 ) AS number_of_rows FROM #TMP WHERE "Leading column Type" = 'Ascending' ORDER BY number_of_rows DESC
The T-SQL query that will collect data
Instances to collect from
Select all
Databases to collect from
1
Collection frequency
86400
Use collected or calculated values
Leave the Use a calculated rate of change between collections check box unchecked
Metric collection
Enabled
Alert definition
Alert name
Increased number of ascending statistics
Description
After finding these columns, look at the queries on those tables to make sure you are getting an optimized plan for the query.
For more information, see http://www.simple-talk.com/sql/database-administration/statistics-on-ascending-columns/
The following query can be used to help you analyze which statistics are “branded” as ascending:
DBCC TRACEON(2388) WITH NO_INFOMSGS SET NOCOUNT ON IF OBJECT_ID('tempdb.dbo.#TMP_stats') IS NOT NULL DROP TABLE #TMP_stats IF OBJECT_ID('tempdb.dbo.#TMP') IS NOT NULL DROP TABLE #TMP CREATE TABLE #TMP ( ROWID INT IDENTITY(1, 1) PRIMARY KEY, TableName NVARCHAR(800), StatsName NVARCHAR(800), "Updated" NVARCHAR(800), "Table Cardinality" BIGINT, "Snapshot Ctr" BIGINT, "Steps" BIGINT, "Density" FLOAT, "Rows Above" FLOAT, "Rows Below" FLOAT, "Squared Variance Error" FLOAT, "Inserts Since Last Update" FLOAT, "Deletes Since Last Update" FLOAT, "Leading column Type" NVARCHAR(200) ); WITH CTE_1 AS (SELECT OBJECT_SCHEMA_NAME(a.object_id) schemaname, OBJECT_NAME(a.object_id) AS 'TableName', a.name AS 'StatsName', STATS_DATE(a.object_id, stats_id) AS stats_last_updated_time, (SELECT SUM(p.rows) FROM sys.partitions p WHERE a.object_id = p.object_id AND index_id <= 1 ) AS number_of_rows FROM sys.stats AS a INNER JOIN sys.objects AS b ON a.object_id = b.object_id WHERE b.type = 'U' ) SELECT IDENTITY( INT , 1,1 ) ROWID, *, 'DBCC SHOW_STATISTICS ("' + schemaname + '.' + tablename + '",' + statsname + ') WITH NO_INFOMSGS' AS SQL INTO #TMP_stats FROM CTE_1 WHERE number_of_rows > 1000 CREATE CLUSTERED INDEX ix ON #TMP_stats(ROWID) DECLARE @SQL NVARCHAR(MAX), @TableName NVARCHAR(800), @StatsName NVARCHAR(800), @ROWID INT, @LastID INT, @MaxID INT SELECT @ROWID = 0, @SQL = '', @TableName = '', @StatsName = '', @LastID = 0, @MaxID = 2147483647 SELECT TOP 1 @ROWID = ROWID, @SQL = SQL, @TableName = TableName, @StatsName = StatsName FROM #TMP_stats WHERE ROWID > @ROWID ORDER BY ROWID WHILE @@ROWCOUNT > 0 BEGIN PRINT @SQL INSERT INTO #TMP ("Updated", "Table Cardinality", "Snapshot Ctr", "Steps", "Density", "Rows Above", "Rows Below", "Squared Variance Error", "Inserts Since Last Update", "Deletes Since Last Update", "Leading column Type") EXEC (@SQL) SELECT @LastID = MIN(ROWID), @MaxID = MAX(ROWID) FROM #TMP WHERE ROWID BETWEEN (SELECT MIN(a.ROWID) FROM #TMP a WHERE a.TableName IS NULL ) AND (SELECT MAX(b.ROWID) FROM #TMP b WHERE b.TableName IS NULL ) UPDATE #TMP SET TableName = @TableName, StatsName = @StatsName WHERE ROWID BETWEEN @LastID AND @MaxID SELECT TOP 1 @ROWID = ROWID, @SQL = SQL, @TableName = TableName, @StatsName = StatsName FROM #TMP_stats WHERE ROWID > @ROWID ORDER BY ROWID END DBCC TRACEOFF(2388) WITH NO_INFOMSGS SELECT TableName, StatsName, (SELECT SUM(p.rows) FROM sys.partitions p WHERE OBJECT_ID(TableName) = p.object_id AND index_id <= 1 ) AS number_of_rows FROM #TMP WHERE "Leading column Type" = 'Ascending' ORDER BY number_of_rows DESC
Raise an alert when the metric value goes
Above the defined threshholds
Default threshold values
High: | 50 |
Medium: | 10 |
Low: | 0 |
Note: These thresholds are intended as guideline values. If they seem too high or too low for your environment, replace them with values more suited to your server performance.
Raise an alert when the threshold is passed for
1 collection
Alert is
Enabled