這陣子我們系統的錯誤通知出現了一個沒看過的訊息:
The query processor could not start the necessary thread resources for parallel query execution.
翻成中文是「查詢處理器無法為平行查詢的執行啟動必要的執行緒資源」,簡單來說就是「資料庫很忙,執行緒不夠用。
」,而且根據幾個關鍵字 Thread
、Parallel
、Query
,我們也大概能知道是平行處理的問題,知道了方向就可以開始著手調查了。
首先,我確定了出問題的是一串用 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 在產生執行計劃的時候選擇比較有效率的計劃節點。
另外,如果我們在網路上搜尋相關的解決方法,大都會找到下面這兩種:
- 加入 OPTION (MAXDOP 1) 查詢提示
- 將伺服器組態選項 Max Degree of Parallelism 設定為 1
但是,我個人認為資料庫這個領域水很深,關於這種伺服器層級的設定,儘量不去做調整,應該先從資料表的設計
、索引的規劃
、查詢的語句
這些地方看看有沒有什麼問題?如果找不到問題,想要修改伺服器層級的設定,也應該做好充分的研究跟測試,清楚瞭解調整設定的風險,這樣再來下手會比較穩妥一些。
參考資料
- 認識平行(parallelism)處理,以MAXDOP、cost threshold for parallelism與max degree of parallelism選項為例
- 設定 max degree of parallelism 伺服器組態選項