Sql-Server

了解查詢儲存不尊重強制計劃時的計劃選擇

  • August 27, 2019

我試圖找出上週遇到的一種情況,為了在事件期間臨時修復計劃回歸,我使用 Query Store 強制執行計劃,但發現它沒有按預期工作。我已經閱讀了 Andrew Kelly 關於強迫並不總是意味著強迫的文章,並認為這可能是我所看到的,但我希望對它有更多的了解,因為在我的情況下,計劃與我的不同d 期望。我還查看了有關計劃強制的查詢儲存文件的計劃強制限制部分,但我認為這裡的任何限制都不適用。

查詢儲存中的視圖如下所示 - 大約 8:30 出現了一個成本更高的新計劃(2.14178 vs 0.894238),我強制執行之前使用的計劃。從圖中可以看出,儘管我已經強制執行舊計劃,但從此時起,新計劃仍會針對查詢的指標顯示:

查詢儲存強制計劃

查看 sys.query_store_plan,我可以看到舊計劃顯示為強制,並且沒有任何反對意見表明強制執行失敗:

[

奇怪的是,當我後來查看計劃記憶體時,這些計劃都沒有使用,儘管使用的計劃確實具有與上面顯示的計劃 13449 相同的查詢計劃雜湊值,儘管有很大不同。實際使用的計劃的估計成本要高得多,為 72.6743。

我從每個計劃中獲取了編譯後的值,並對其中三個進行了查詢,以了解計劃的實際指標是什麼樣的,並且這些值與估計值有很大不同。值得注意的是,我從記憶體中獲取的計劃產生了約 400 MB 的記憶體授權,因為它使用不同的索引並且必須對數據進行排序,而其他 2 個計劃的 8 MB 記憶體授權沒有排序。三個計劃的估計成本有點接近,但查詢儲存中的 2 的估計成本比查詢儲存中顯示的計劃高得多。

這是發生的查詢:

(
   @id_group int,
   @create_date datetime,
   @rows_per_page int,
   @page_number int
)
SELECT *
FROM ts_customer
WHERE 
   id_group = @id_group 
   AND enabled = 'Y'
   AND (create_date >= @create_date)
ORDER BY 
   full_name, 
   id_customer desc
offset 
   ((@page_number - 1) * @rows_per_page) rows
   fetch next @rows_per_page rows only

誰能幫我理解為什麼該計劃沒有被強制執行,以及為什麼正在使用的計劃要貴得多?

我知道這select *將導致大記憶體授予,因為它是一個寬表,但我主要是想了解這裡使用查詢儲存看到的行為,並且在較小程度上,為什麼使用計劃而不是強制計劃它使用不同的索引並且必須進行排序。

發生這種情況的數據庫在 Azure SQL DB 上執行,兼容級別為 140,並使用舊的基數估計器。

我附上了所有 3 個估計的計劃,以及當我使用每組編譯值執行查詢時生成的計劃。這些可以在這裡訪問。

誰能幫我理解為什麼不強制執行該計劃

查看計劃 XML,計劃 id 6194 是在版本 15.0 上編譯的。SQL Server 的700.539,而計劃 ID 13449 是在版本 15.0 上編譯的。900.210

兩個計劃之間唯一值得注意的區別(除了基數估計)是:

計算標量受行目標的影響(由於隱含TOP的 from OFFSET / FETCH):

EstimateRowsWithoutRowGoal="170.008"

NL 連接使用無序預取進行了優化:

<NestedLoops Optimized="true" WithUnorderedPrefetch="true">

似乎這些細微的差異導致了您連結到的 Andrew Kelly 的文章中描述的問題。該計劃基本相同,實施方式略有不同。格蘭特弗里奇對此進行瞭如下描述:

有一種相對模糊的情況,可以使用“道德等效”計劃,即所有核心要素相同但不一定完全相同的計劃,而不是您定義的精確計劃。然而,這並不常見。

來自他關於執行計劃的免費電子書的第 473 頁。

為什麼正在使用的那個要貴得多?

使用中真正昂貴的計劃有 4 個額外的列,所以我認為這並不是真正將蘋果與蘋果進行比較。較高的成本似乎主要是由於使用的參數(因此較高的基數估計)。順便說一句,它在另一個完全不同的版本上:15.0。1300.566。事情確實在雲中快速移動 =P

這些都是來自以下的“新”列SELECT *

<ColumnReference Database="[app-live-au]" Schema="[dbo]" Table="[ts_customer]" Column="delete_requested_date_utc" />
<ColumnReference Database="[app-live-au]" Schema="[dbo]" Table="[ts_customer]" Column="retention_policy_applied_date_utc" />
<ColumnReference Database="[app-live-au]" Schema="[dbo]" Table="[ts_customer]" Column="retention_policy_type" />
<ColumnReference Database="[app-live-au]" Schema="[dbo]" Table="[ts_customer]" Column="id_portal_user" />

您提供的組合測試都與這個最新版本的東西一致。

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