增量统计:找出哪些分区已被重新采样

von*_*ryz 4 sql-server statistics dmv partitioning sql-server-2014

TL;DR:在使用增量统计数据时,是否可以找出哪些分区已重新采样,哪些未重新采样?平台为 SQL Server 2014 企业版。

带有一些背景信息的长版本是这样的。

假设一个相当典型的 DW 环境,有一个分区表。分区基于日期列。这是因为将暂存数据加载到单独的表上,并且在预处理之后,使用分区切换将数据移动到生产事实表中。哦,一个聚集列存储索引正在使用中。使用了大约一千个分区。数据库在虚拟机上运行。

事实表中有大约 7.5 gigarows (100 GB)。每日增长约为 5 兆。这个增长率太小,无法触发自动统计更新,保存跟踪标志 2371(尚未尝试)。

开发人员对过时统计数据的下意识反应是更新它们。对于 7.5 gigarows,所有统计数据的完整更新需要大约五个小时。对于单个统计更新,处理性能约为每秒 20 分钟或 90 兆行。

由于系统位于 VM 平台上,因此业务规则限制了其成本。内存和 IOPS 都不容易增加。五小时的更新工作太慢,无法包含在每晚的 ETL 过程中,因此统计数据要么过时,要么在意外的时间更新,要么将在维护窗口中更新。

由于 SQL Server 是 2014 企业版,它支持增量统计,听起来就像解决方案。将统计信息转换为增量统计信息后,处理单个分区的单个统计信息只需 20 秒。新切换的分区总计约五分钟。这听起来很棒,当然也适合 ETL 过程。

我想知道的是如何在分区切换环境中管理增量统计信息。假设统计数据在日期 D 被转换和更新为增量,那么如何找出未处理的分区,例如,日期 D+2?在 ETL 过程中更新统计信息是微不足道的,因为切换过程显然知道分区 ID。但是,如果存在未重新采样的分区,如何找到这些分区?

  • 可以从以下位置找到统计数据的最后更新 sys.dm_db_stats_properties
  • 分区号可从 sys.partitions
  • 分区函数值在 sys.partition_range_values

可以选择统计数据的最后更新日期 L 并将其与今天的日期 T 进行比较。然后计算 L 指向哪个分区 id 以及它是否与 T 相同。然后继续更新所有分区 ID [L, T)。这听起来很棘手且容易出错,那么有更好的方法吗?显示哪些分区用于重采样的 DMV 会很好,但没有,是吗?

swa*_*eck 7

我的第一个问题是问你为什么实际上首先使用增量。这是我发布的关于增量统计的答案,Erin Stellato的一篇博客文章阐明了增量统计的主要抱怨和陷阱之一(优化器未在分区级别使用它们),以及我的两篇 博客文章通过评估增量统计的任何潜在用例来工作。

话虽如此,要知道何时对分区的统计信息进行了采样,您可以使用未记录的 DMF ( sys.dm_db_stats_properties_internal()) 来获取分区级别的信息。我对这篇博文有一个评论,它描述了如何在相当高的层次上理解层次结构。

select 
    sysdatetime(),                          
    schema_name = sh.name,
    table_name = t.name,
    stat_name = s.name,
    index_name = i.name,
    leading_column = index_col(quotename(sh.name)+'.'+quotename(t.name),s.stats_id,1),
    s.stats_id,
    parition_number = isnull(sp.partition_number,1),
    s.has_filter,                       
    s.is_incremental,
    s.auto_created,
    sp.last_updated,    
    sp.rows,
    sp.rows_sampled,                        
    sp.unfiltered_rows,
    modification_counter = coalesce(sp.modification_counter, n1.modification_counter) 
from sys.stats s 
join sys.tables t 
    on s.object_id = t.object_id
join sys.schemas sh
    on t.schema_id = sh.schema_id
left join sys.indexes i 
    on s.object_id = i.object_id
        and s.name = i.name
cross apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) sp
outer apply sys.dm_db_stats_properties_internal(s.object_id, s.stats_id) n1
where n1.node_id = 1
    and (
            (is_incremental = 0)
               or
            (is_incremental = 1 and sp.partition_number is not null)
         )
    and t.name = '<<TABLENAME>>'
    and s.name like '<<STATNAME>>%'
order by s.stats_id,isnull(sp.partition_number,1);
Run Code Online (Sandbox Code Playgroud)