為什麼我的統計數據這麼快就過時了?
我有一個大表(3 億行),每天添加大約 100 萬行。這是時間序列數據,所以我有以下設置:
CREATE TABLE Readings ( Id INT PRIMARY KEY, TrackerId INT, DateProcessed DATETIME, -- About 10 other columns of data ) CREATE INDEX IX_TrackerId_DateProcessed ON Readings ( TrackerId, DateProcessed ) INCLUDE ( -- all the other columns ) WHERE ( TrackerId IS NOT NULL )
當我們查看數據時,我通常會執行如下查詢:
SELECT Latest.* FROM Trackers CROSS APPLY ( SELECT TOP 1 * FROM Readings WHERE TrackerId = Trackers.Id ORDER BY DateProcessed DESC ) Latest
這曾經工作得很好。現在,生成查詢計劃需要很長時間,即使我明確告訴它使用索引。到目前為止,我發現的唯一解決方案是使用以下命令更新表的統計資訊:
UPDATE STATISTICS Readings
這大約需要十分鐘才能執行,然後選擇查詢執行良好,但只執行一天。然後我必須再次更新統計資訊。為什麼統計數據過時如此之快,我能做些什麼來防止這種情況發生?
值得一提的點:
- 我只追加到表中,我從不更新或刪除行
- 有一些舊行的 tracker id 值為空,但不會再添加
- 數據庫以兼容級別 14 執行
- 我無法在 Azure SQL 中啟用跟踪標誌 2371
評論中問題的其他答案
更新統計數據之前和之後的計劃對我來說是一樣的。問題不在於我得到了一個糟糕的查詢計劃,而在於獲得該計劃*需要多長時間。*在更新統計數據之前,我不得不等待兩分鐘的計劃。更新統計數據後,它立即得到了計劃。
在寫這篇文章時,我剛剛意識到等待查詢實際上會更快,讓記憶體來完成工作,而不是更新統計資訊,但這仍然不能解決問題。此查詢是在 Entity Framework 中執行的,超時時間為 30 秒,因此兩分鐘仍然太長。
自動更新統計資訊所花費的時間包含在編譯時間中。統計資訊更新需要 10 分鐘,觸發自動統計資訊更新的查詢的編譯時間包括該時間 - 這就是查詢時不時需要超過 10 分鐘的原因。
根據文件,自動統計更新的修改門檻值為
sqrt(table cardinality * 1000)
使用您的數字(300,000,000 行),您達到了 547,722 次修改的門檻值。
由於每天要添加 1,000,000 行,因此您必須每天兩次左右自動更新統計資訊。
由於您的查詢估計在統計資訊更新前後都很好,因此一種可能的解決方案是啟用數據庫級別
AUTO_UPDATE_STATISTICS_ASYNC
設置。這仍然讓 SQL Server 自動更新統計資訊,但它是非同步完成的(因此查詢不必等待它發生):ALTER DATABASE [Live] SET AUTO_UPDATE_STATISTICS_ASYNC ON;
請注意,這會影響整個數據庫,而不僅僅是該表/統計資訊。