Sql-Server

增量統計:找出哪些分區已被重新採樣

  • March 16, 2016

**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 會很好,但沒有一個,是嗎?

我的第一個問題是首先問為什麼你實際上使用增量。這是我發布的關於增量統計的答案,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);

引用自:https://dba.stackexchange.com/questions/132193