经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 数据库/运维 » MS SQL Server » 查看文章
SQL Server 查找统计信息的相关采样信息
来源:cnblogs  作者:潇湘隐者  时间:2019/2/19 9:24:48  对本文有异议

SQL Server 查找统计信息的相关采样信息

 

有时候我们会遇到,由于统计信息不准确导致优化器生成了一个错误的执行计划(或者这样表达:一个较差的执行计划),从而引起了系统性能问题。那么如果我们怀疑这个错误的执行计划是由于统计信息不准确引起的。那么我们如何判断统计信息不准确呢?当然首先得去查看实际执行计划中,统计信息的相关数据是否与实际情况有较大的出入,下面我们抛开这个大命题,仅仅从统计信息层面去查看统计信息的更新时间,统计信息的采样行数等情况。

 

1:首先,我们要查查统计信息是什么时候更新的。

 

2:其次,我们查看统计信息的采样信息:采样选取的行数、自上次更新统计信息以来前导统计信息列(构建直方图的列)的总修改次数。。。 

 

查看统计信息的最后更新时间。

 

方法1:

 

  1. --查看统计信息的更新时间
  1. DECLARE @TableName NVARCHAR(128);
  1. SET @TableName = 'dbo.pbCutClothCost';
  1. SELECT  @TableName  AS Table_Name,
  1.         name AS Stats_Name ,
  1.         STATS_DATE(object_id, stats_id) AS Last_Stats_Update
  1. FROM    sys.stats
  1. WHERE   object_id = OBJECT_ID(@TableName)
  1. ORDER BY 2 DESC;

 

 

 

clip_image001

 

 

如上所示,我们通过这个脚本查看某个表,所有的统计信息最后一次更新时间。如果你需要查看某个具体的统计信息的最后更新时间,那么在这个SQL的基础上增加相关查询条件即可。

 

方法2:

 

 

--查看统计信息的更新时间

EXEC sp_autostats 'dbo.pbCutClothCost';

 

 

方法3:

 

还有一种方法可以通过 sys.dm_db_stats_properties 返回统计信息的更新时间,不过这个DMF只有SQL Server 2008 R2 SP2这个版本之后的才有。

 

列名

数据类型

Description

object_id

int

要返回统计信息对象属性的对象(表或索引视图)的 ID

stats_id

int

统计信息对象的 ID 在表或索引视图中是唯一的。 有关详细信息,请参阅 sys.stats (Transact-SQL)

last_updated

datetime2

上次更新统计信息对象的日期和时间。 有关详细信息,请参阅此页中的备注部分。

rows

bigint

上次更新统计信息时表或索引视图中的总行数。 如果筛选统计信息或者统计信息与筛选索引对应,该行数可能小于表中的行数。

rows_sampled

bigint

用于统计信息计算的抽样总行数。

Step

int

直方图中的值范围数(步长)(Number of steps in the histogram)。 有关详细信息,请参阅 DBCC SHOW_STATISTICS (Transact-SQL)

unfiltered_rows

bigint

应用筛选表达式(用于筛选的统计信息)之前表中的总行数。 如果未筛选统计信息,则 unfiltered_rows 等于行列中返回的值。

modification_counter

bigint

自上次更新统计信息以来前导统计信息列(构建直方图的列)的总修改次数。

内存优化表: 正在启动SQL Server 2016 (13.x)并在Azure SQL Database此列包含: 修改因为最后一个时间统计信息已更新或重新启动数据库的表的总次数。

persisted_sample_percent

float

持久样本百分比用于未显式指定采样百分比的统计信息更新。 如果值为零,则不为此统计信息设置持久样本百分比。

适用范围:SQL Server 2016 (13.x)
 
SP1 CU4

 

 

 

查看采样的相关信息

 

 

 

  1. SELECT sch.name + '.' + so.name AS table_name
  1.       , so.object_id
  1.       , ss.name  AS stat_name
  1.       , ds.stats_id
  1.       , ds.last_updated
  1.       , ds.rows
  1.       , ds.rows_sampled
  1.       , ds.steps
  1.       , ds.unfiltered_rows
  1.       , ds.modification_counter
  1. FROM sys.stats ss
  1. JOIN sys.objects so ON ss.object_id = so.object_id
  1. JOIN sys.schemas sch ON so.schema_id = sch.schema_id
  1. CROSS APPLY sys.dm_db_stats_properties(ss.object_id,ss.stats_id) ds
  1. WHERE so.name =  N'pbCutClothCost'
  1.     AND   LEFT(ss.name, 4) != '_WA_';

 

 

clip_image002

 

 

如上截图,索引IX_CutClothCost的统计信息有更新,是因为在执行上面脚本,我更新了这个索引的统计信息。通过rows与实际记录数对比、 modification_counter信息,我们从而有个大概的判断,这些统计信息是否过时。是否采样的比例太小等。

  1. SELECT sch.name + '.' + so.name AS table_name
  1.       , so.object_id
  1.       , ss.name  AS stat_name
  1.       , ds.stats_id
  1.       , ds.last_updated
  1.       , ds.rows
  1.       , ds.rows_sampled
  1.       , ds.rows_sampled/ds.rows *100 AS sample_rate
  1.       , ds.steps
  1.       , ds.unfiltered_rows
  1.       , ds.modification_counter
  1. FROM sys.stats ss
  1. JOIN sys.objects so ON ss.object_id = so.object_id
  1. JOIN sys.schemas sch ON so.schema_id = sch.schema_id
  1. CROSS APPLY sys.dm_db_stats_properties(ss.object_id,ss.stats_id) ds
  1. WHERE so.name =  N'pbCutClothCost'
  1.     AND   LEFT(ss.name, 4) != '_WA_';

 

 

 

当然也可以使用DBCC SHOW_STATISTICS来查看统计信息的详细信息。

 

DBCC SHOW_STATISTICS ('dbo.pbCutClothCost', IX_pbCutClothCost_N1)

 

 

 

另外一个维度来判别统计信息过时,是通过时间维度(最后一次统计信息更新距今的时间)。这个相关上面维度的数据而言,往往不是特别准确,但是也有参考意义。

 

  1. SELECT
  1.     sch.name + '.' + so.name AS "Table",
  1.     ss.name                     AS"Statistic",
  1.     CASE
  1.         WHEN ss.auto_Created = 0 AND ss.user_created = 0 THEN  'Index Statistic'
  1.         WHEN ss.auto_created = 0 AND ss.user_created = 1 THEN  'USER Created'
  1.         WHEN ss.auto_created = 1 AND ss.user_created = 0 THEN  'Auto Created'
  1.         WHEN ss.AUTO_created = 1 AND ss.user_created = 1 THEN  'Not Possible'
  1.     END AS
  1.     "Statistic Type",
  1.     CASE
  1.             WHEN ss.has_filter = 1 THEN  'Filtered INDEX'
  1.             WHEN ss.has_filter = 0 THEN  'No Filter'
  1.       END AS "Filtered",
  1.     CASE
  1.             WHEN ss.filter_definition IS NULL THEN ''
  1.             WHEN ss.filter_definition IS NOT NULL THEN ss.filter_definition
  1.  
  1.     END AS "Filter Definition",
  1.     sp.last_updated AS "Stats Last Updated",
  1.     sp.rows AS "Rows",
  1.     sp.rows_sampled AS "Rows Sampled",
  1.     sp.unfiltered_rows AS "Unfiltered Rows",
  1.     sp.modification_counter AS "Row Modifications",
  1.     sp.steps AS "Histogram Steps"
  1. FROM sys.stats ss
  1. JOIN sys.objects so ON ss.object_id = so.object_id
  1. JOIN sys.schemas sch ON so.schema_id = sch.schema_id
  1. OUTER APPLY sys.dm_db_stats_properties(so.object_id, ss.stats_id) AS sp
  1. WHERE so.TYPE = 'U'
  1.     AND sp.last_updated < GETDATE() - 7
  1. ORDER BY sp.last_updated DESC;

 

以前收集过一个查询过时的统计信息的脚本(忘记出自哪里了),这个是通过Max(ApproximateRows) > 500 AND Max(RowModCtr) > (Max(ApproximateRows)*0.2 + 500 )来找出过时的统计信息。如下所示

 

  1. DECLARE @Major INT ,
  1.     @Minor INT ,
  1.     @build INT ,
  1.     @revision INT ,
  1.     @i INT ,
  1.     @str NVARCHAR(100) ,
  1.     @str2 NVARCHAR(10);
  1.  
  1.  
  1.  
  1. SET @str = CAST(SERVERPROPERTY('ProductVersion') AS NVARCHAR(100));
  1.  
  1.  
  1.  
  1. SET @str2 = LEFT(@str, CHARINDEX('.', @str));
  1.  
  1. SET @i = LEN(@str);
  1.  
  1. SET @str = RIGHT(@str, @i - CHARINDEX('.', @str));
  1.  
  1. SET @Major = CAST(REPLACE(@str2, '.', '') AS INT);
  1.  
  1. SET @str2 = LEFT(@str, CHARINDEX('.', @str));
  1.  
  1. SET @i = LEN(@str);
  1.  
  1. SET @str = RIGHT(@str, @i - CHARINDEX('.', @str));
  1.  
  1. SET @Minor = CAST(REPLACE(@str2, '.', '') AS INT);
  1.  
  1. SET @str2 = LEFT(@str, CHARINDEX('.', @str));
  1.  
  1. SET @i = LEN(@str);
  1.  
  1. SET @str = RIGHT(@str, @i - CHARINDEX('.', @str));
  1.  
  1. SET @build = CAST(REPLACE(@str2, '.', '') AS INT);
  1.  
  1. SET @revision = CAST(@str AS INT);
  1.  
  1.  
  1.  
  1.  
  1.  
  1.  
  1.  
  1. IF @Major < 10
  1.     SET @i = 1;
  1.  
  1. ELSE
  1.     IF @Major > 10
  1.         SET @i = 0;
  1.  
  1.     ELSE
  1.         IF @Minor = 50
  1.             AND @build >= 4000
  1.             SET @i = 0;
  1.  
  1.         ELSE
  1.             SET @i = 1;
  1.  
  1.  
  1.  
  1. IF @i = 1
  1.     BEGIN
  1.  
  1.         EXEC sp_executesql N';WITH StatTables AS(
  1.  
  1.             SELECT     so.schema_id AS ''schema_id'',    
  1.  
  1.                        so.name  AS ''TableName'',
  1.  
  1.                        so.object_id AS ''object_id'',
  1.  
  1.                        CASE indexproperty(so.object_id, dmv.name, ''IsStatistics'')
  1.  
  1.                                 WHEN 0 THEN dmv.rows
  1.  
  1.                                 ELSE (SELECT TOP 1 row_count FROM sys.dm_db_partition_stats ps (NOLOCK) WHERE ps.object_id=so.object_id AND ps.index_id in (1,0))
  1.  
  1.                        END AS ''ApproximateRows'',
  1.  
  1.                        dmv.rowmodctr AS ''RowModCtr''
  1.  
  1.             FROM sys.objects so (NOLOCK)
  1.  
  1.                 INNER JOIN sysindexes dmv (NOLOCK) ON so.object_id = dmv.id
  1.  
  1.                 LEFT JOIN sys.indexes si (NOLOCK) ON so.object_id = si.object_id AND so.type in (''U'',''V'') AND si.index_id  = dmv.indid
  1.  
  1.             WHERE so.is_ms_shipped = 0
  1.  
  1.                 AND dmv.indid<>0
  1.  
  1.                 AND so.object_id not in (SELECT major_id FROM sys.extended_properties (NOLOCK) WHERE name = N''microsoft_database_tools_support'')
  1.  
  1.         ),
  1.  
  1.         StatTableGrouped AS
  1.  
  1.         (
  1.  
  1.         SELECT
  1.  
  1.             ROW_NUMBER() OVER(ORDER BY TableName) AS seq1,
  1.  
  1.             ROW_NUMBER() OVER(ORDER BY TableName DESC) AS seq2,
  1.  
  1.             TableName,
  1.  
  1.             cast(Max(ApproximateRows) AS bigint) AS ApproximateRows,
  1.  
  1.             cast(Max(RowModCtr) AS bigint) AS RowModCtr,
  1.  
  1.             schema_id,object_id
  1.  
  1.         FROM StatTables st
  1.  
  1.         GROUP BY schema_id,object_id,TableName
  1.  
  1.         HAVING (Max(ApproximateRows) > 500 AND Max(RowModCtr) > (Max(ApproximateRows)*0.2 + 500 ))
  1.  
  1.         )
  1.  
  1.         SELECT
  1.  
  1.             @@SERVERNAME AS InstanceName,
  1.  
  1.             seq1 + seq2 - 1 AS NbOccurences,
  1.  
  1.             SCHEMA_NAME(stg.schema_id) AS ''SchemaName'',
  1.  
  1.             stg.TableName,
  1.  
  1.             CASE OBJECTPROPERTY(stg.object_id, ''TableHasClustIndex'')
  1.  
  1.                            WHEN 1 THEN ''Clustered''
  1.  
  1.                            WHEN 0 THEN ''Heap''
  1.  
  1.                            ELSE ''Indexed View''
  1.  
  1.                      END AS ClusteredHeap,
  1.  
  1.             CASE objectproperty(stg.object_id, ''TableHasClustIndex'')
  1.  
  1.                             WHEN 0 THEN (SELECT count(*) FROM sys.indexes i (NOLOCK) where i.object_id= stg.object_id) - 1
  1.  
  1.                             ELSE (SELECT count(*) FROM sys.indexes i  (NOLOCK) where i.object_id= stg.object_id)
  1.  
  1.                 END AS IndexCount,
  1.  
  1.             (SELECT count(*) FROM sys.columns c (NOLOCK) WHERE c.object_id = stg.object_id ) AS ColumnCount ,
  1.  
  1.             (SELECT count(*) FROM sys.stats s (NOLOCK) WHERE s.object_id = stg.object_id) AS StatCount ,
  1.  
  1.             stg.ApproximateRows,
  1.  
  1.             stg.RowModCtr,
  1.  
  1.             stg.schema_id,
  1.  
  1.             stg.object_id
  1.  
  1.         FROM StatTableGrouped stg';
  1.  
  1.     END;
  1.  
  1. ELSE
  1.     BEGIN
  1.  
  1.         EXEC sp_executesql N';WITH StatTables AS(
  1.  
  1.             SELECT     so.schema_id AS ''schema_id'',    
  1.  
  1.                             so.name  AS ''TableName'',
  1.  
  1.                 so.object_id AS ''object_id''
  1.  
  1.                 , ISNULL(sp.rows,0) AS ''ApproximateRows''
  1.  
  1.                 , ISNULL(sp.modification_counter,0) AS ''RowModCtr''
  1.  
  1.             FROM sys.objects so (NOLOCK)
  1.  
  1.                 JOIN sys.stats st (NOLOCK) ON so.object_id=st.object_id
  1.  
  1.                 CROSS APPLY sys.dm_db_stats_properties(so.object_id, st.stats_id) AS sp
  1.  
  1.             WHERE so.is_ms_shipped = 0
  1.  
  1.                 AND st.stats_id<>0
  1.  
  1.                 AND so.object_id not in (SELECT major_id FROM sys.extended_properties (NOLOCK) WHERE name = N''microsoft_database_tools_support'')
  1.  
  1.         ),
  1.  
  1.         StatTableGrouped AS
  1.  
  1.         (
  1.  
  1.         SELECT
  1.  
  1.             ROW_NUMBER() OVER(ORDER BY TableName) AS seq1,
  1.  
  1.             ROW_NUMBER() OVER(ORDER BY TableName DESC) AS seq2,
  1.  
  1.             TableName,
  1.  
  1.             cast(Max(ApproximateRows) AS bigint) AS ApproximateRows,
  1.  
  1.             cast(Max(RowModCtr) AS bigint) AS RowModCtr,
  1.  
  1.             count(*) AS StatCount,
  1.  
  1.             schema_id,object_id
  1.  
  1.         FROM StatTables st
  1.  
  1.         GROUP BY schema_id,object_id,TableName
  1.  
  1.         HAVING (Max(ApproximateRows) > 500 AND Max(RowModCtr) > (Max(ApproximateRows)*0.2 + 500 ))
  1.  
  1.         )
  1.  
  1.         SELECT
  1.  
  1.             @@SERVERNAME AS InstanceName,
  1.  
  1.             seq1 + seq2 - 1 AS NbOccurences,
  1.  
  1.             SCHEMA_NAME(stg.schema_id) AS ''SchemaName'',
  1.  
  1.             stg.TableName,
  1.  
  1.             CASE OBJECTPROPERTY(stg.object_id, ''TableHasClustIndex'')
  1.  
  1.                            WHEN 1 THEN ''Clustered''
  1.  
  1.                            WHEN 0 THEN ''Heap''
  1.  
  1.                            ELSE ''Indexed View''
  1.  
  1.                      END AS ClusteredHeap,
  1.  
  1.             CASE objectproperty(stg.object_id, ''TableHasClustIndex'')
  1.  
  1.                             WHEN 0 THEN (SELECT count(*) FROM sys.indexes i (NOLOCK) where i.object_id= stg.object_id) - 1
  1.  
  1.                             ELSE (SELECT count(*) FROM sys.indexes i (NOLOCK) where i.object_id= stg.object_id)
  1.  
  1.                 END AS IndexCount,
  1.  
  1.             (SELECT count(*) FROM sys.columns c (NOLOCK) WHERE c.object_id = stg.object_id ) AS ColumnCount ,
  1.  
  1.             stg.StatCount,
  1.  
  1.             stg.ApproximateRows,
  1.  
  1.             stg.RowModCtr,
  1.  
  1.             stg.schema_id,
  1.  
  1.             stg.object_id
  1.  
  1.         FROM StatTableGrouped stg';
  1.  
  1.     END;

 

 

 

参考资料:

 

https://www.sqlskills.com/blogs/erin/new-statistics-dmf-in-sql-server-2008r2-sp2/

原文链接:http://www.cnblogs.com/kerrycode/p/10396407.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号