[廚餘回收] 嘗試解決 SQL Server 查詢處理器無法為平行查詢的執行啟動必要的執行緒資源(The query processor could not start the necessary thread resources for parallel query execution.)的問題

這陣子我們系統的錯誤通知出現了一個沒看過的訊息:

The query processor could not start the necessary thread resources for parallel query execution.

翻成中文是「查詢處理器無法為平行查詢的執行啟動必要的執行緒資源」,簡單來說就是「資料庫很忙,執行緒不夠用。」,而且根據幾個關鍵字 ThreadParallelQuery,我們也大概能知道是平行處理的問題,知道了方向就可以開始著手調查了。

首先,我確定了出問題的是一串用 GROUP BY 語法來撈出日期清單的查詢語句,我在測試環境重現了這段查詢語句:

SELECT TOP 15
    *
FROM (SELECT
        tm.[Date]
    FROM TestMis tm WITH (NOLOCK)
    GROUP BY tm.[Date]) t
ORDER BY t.[Date] DESC

很單純的一段查詢語句,但是它的查詢計劃卻用了平行處理。

再看了一下它的索引,只有主索引鍵的叢集索引,而且 Date 欄位在叢集索引裡面是第二順位。

為欄位建立索引

到這邊我大致上知道問題的原因了,由於只有位於第一順位的 No 欄位是有排序過的,所以要用 Date 欄位做條件,使用叢集索引必須對 Date 欄位重新排序過,又因為資料筆數已經多到一個程度,才讓 QO(Query Optimizer)選擇使用平行處理。

所以解決的方法就簡單了,單獨為 Date 欄位建一個索引出來,這樣就可以暫時避掉平行處理了。

增加查詢條件

另一個方式是可以增加查詢條件,挑一個 No 欄位裡面合適的資料拿來當條件,縮小資料列數目,而我個人是比較傾向於使用這種方式的,不僅能夠有很大的機會避免平行處理,也能讓 QO 在產生執行計劃的時候選擇比較有效率的計劃節點。

另外,如果我們在網路上搜尋相關的解決方法,大都會找到下面這兩種:

  1. 加入 OPTION (MAXDOP 1) 查詢提示
  2. 將伺服器組態選項 Max Degree of Parallelism 設定為 1

但是,我個人認為資料庫這個領域水很深,關於這種伺服器層級的設定,儘量不去做調整,應該先從資料表的設計索引的規劃查詢的語句這些地方看看有沒有什麼問題?如果找不到問題,想要修改伺服器層級的設定,也應該做好充分的研究跟測試,清楚瞭解調整設定的風險,這樣再來下手會比較穩妥一些。

參考資料

相關資源

C# 指南
ASP.NET 教學
ASP.NET MVC 指引
Azure SQL Database 教學
SQL Server 教學
Xamarin.Forms 教學