如何高效筛选T-SQL中未近月更新的统计信息记录?
好问题!你的核心需求是找出那些完全没在近一个月内更新过的统计项的所有历史记录——换句话说,只有当某个统计项(按TableName+StatisticName组合)的最近一次更新时间早于一个月前,才保留它的所有历史数据。
你之前用逐行子查询的方法虽然能实现效果,但每次查询都要为每行单独执行一次聚合,数据量一大性能肯定会打折扣。下面给你两种更高效的实现方式:
方法1:用CTE预筛选符合条件的统计项组
这种方式只需要一次聚合操作就能找出所有符合要求的统计项,再关联原表拉取所有历史记录,避免了重复计算:
WITH StatisticLatestUpdates AS ( SELECT TableName, StatisticName, MAX(LastUpdated) AS LastUpdatedMax FROM DBA.dbo.StatisticsInfo GROUP BY TableName, StatisticName -- 先筛选出最后更新早于1个月前的组 HAVING MAX(LastUpdated) < DATEADD(MONTH, -1, GETDATE()) ) SELECT si.CollectionTime, ROW_NUMBER() OVER (PARTITION BY si.TableName, si.StatisticName ORDER BY si.CollectionTime) AS Run, si.TableName, si.StatisticName, si.StatisticType, si.ColumnName, si.LastUpdated, slu.LastUpdatedMax, si.Rows, si.RowsSampled, si.HistogramSteps, si.RowsModified FROM DBA.dbo.StatisticsInfo si INNER JOIN StatisticLatestUpdates slu ON si.TableName = slu.TableName AND si.StatisticName = slu.StatisticName;
CTE先把所有统计项的最后更新时间算出来,同时直接过滤掉近一个月有更新的组,之后通过内连接就能快速拿到这些组的全部历史数据。
方法2:用窗口函数一次性标记组的最后更新时间
如果你的SQL Server版本是2012及以上,窗口函数的写法会更简洁,而且性能也不错:
SELECT CollectionTime, Run, TableName, StatisticName, StatisticType, ColumnName, LastUpdated, LastUpdatedMax, Rows, RowsSampled, HistogramSteps, RowsModified FROM ( SELECT CollectionTime, ROW_NUMBER() OVER (PARTITION BY TableName, StatisticName ORDER BY CollectionTime) AS Run, TableName, StatisticName, StatisticType, ColumnName, LastUpdated, -- 给每条记录标记它所属组的最后更新时间 MAX(LastUpdated) OVER (PARTITION BY TableName, StatisticName) AS LastUpdatedMax, Rows, RowsSampled, HistogramSteps, RowsModified FROM DBA.dbo.StatisticsInfo ) AS subQuery -- 只保留组最后更新时间早于1个月前的记录 WHERE LastUpdatedMax < DATEADD(MONTH, -1, GETDATE());
子查询里通过窗口函数MAX() OVER (PARTITION BY ...)一次性计算出每个统计项组的最后更新时间,外层查询直接筛选符合条件的记录即可,全程只需要扫描一次表。
额外性能优化建议
- 给
StatisticsInfo表建一个复合索引:CREATE NONCLUSTERED INDEX IX_StatisticsInfo_TableName_StatisticName_LastUpdated ON DBA.dbo.StatisticsInfo (TableName, StatisticName, LastUpdated) INCLUDE (CollectionTime, StatisticType, ColumnName, Rows, RowsSampled, HistogramSteps, RowsModified);
这个索引能让聚合和窗口函数的计算更快,避免全表扫描。 - 可以对比两种方法的执行计划,数据量极大时CTE的聚合+连接可能略优,窗口函数则胜在写法简洁。
这两种方法都比你原来的逐行子查询高效得多,尤其是数据量上去之后差异会很明显。
内容的提问来源于stack exchange,提问作者mb2o
相关产品推荐
相关产品推荐

