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_propertiessys.partitionssys.partition_range_values可以选择统计数据的最后更新日期 L 并将其与今天的日期 T 进行比较。然后计算 L 指向哪个分区 id 以及它是否与 T 相同。然后继续更新所有分区 ID [L, T)。这听起来很棘手且容易出错,那么有更好的方法吗?显示哪些分区用于重采样的 DMV 会很好,但没有,是吗?
我的第一个问题是问你为什么实际上首先使用增量。这是我发布的关于增量统计的答案,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)
| 归档时间: |
|
| 查看次数: |
947 次 |
| 最近记录: |