連結伺服器查詢導致的阻塞

格瑞趨勢技術團隊發表於2023-02-21

背景

客戶反饋資料庫在上午10點時出現嚴重阻塞,阻塞源頭會話在等待OLEDB,沒有見過這個等待型別,請我們協助分析。

現象

登入SQL專家雲,進入趨勢分析,下鑽到10點鐘的活動會話,看到發生了兩次嚴重的阻塞。

轉到活動會話原始資料,看到阻塞的源頭是會話331,正在執行UPDATE語句,阻塞了其它會話對錶的更新和查詢。

該會話執行了4分32秒,阻塞也持續了這麼長時間,執行完後阻塞消失。

檢視會話331不同時間點的活動會話,看到等待型別都是OLEDB,等待資源都是8.56(連結伺服器目標例項)上的會話589。

分析

會話331對錶執行UPDATE操作,阻塞其它會話對該表的寫入和查詢,這是正常的,也是好理解的。分析的重點是為什麼執行時間這麼長,而且全部都是連結伺服器的等待(OLEDB)。

 

 

 

下載並開啟執行計劃,看到各表之間使用巢狀迴圈來關聯。巢狀迴圈聯接也稱為巢狀迭代,它將一個聯接輸入用作外部輸入表(顯示為圖形執行計劃中的頂端輸入),將另一個聯接輸入用作內部(底端)輸入表。外部迴圈逐行處理外部輸入表。內部迴圈會針對每個外部行執行,在內部輸入表中搜尋匹配行。因此推斷連結伺服器查詢迴圈次數太多導致執行時間長。關於巢狀迴圈聯接和其他的聯接方式參考官方文件:https://docs.microsoft.com/zh-cn/sql/relational-databases/performance/joins?view=sql-server-ver16。

 

在連結伺服器的目標端8.56中,檢視會話589在不同採集時間點的活動會話,看到該會話的請求開始時間、最後請求開始時間、最後請求結束時間三個資料是變化的,執行的SQL語句是一樣的,說明在迴圈執行同一查詢語句。粗略計算執行了3000次左右,從而驗證推斷是正確的。

 

 

解決

修改儲存過程,先把連結伺服器查詢返回結果儲存在臨時表中,然後在UPDATE語句中關聯該臨時表,這樣只會有一次連結伺服器查詢,修改完後執行時間從4分30秒下降到4秒。

總結

客戶反饋這個語句以前執行的很快,解釋是以前的執行計劃使用的是合併聯接或者雜湊聯接,這樣對連結伺服器查詢只有一次。隨著表資料量、統計資訊等指標的變化,執行計劃發生了變更,認為使用巢狀迴圈關聯更合理,但是真正執行的時候卻適得其反。從根源上說還是SQL語句寫法的問題,給了SQL Server多種選擇。

連結伺服器的查詢要跨越網路,響應時間是毫秒甚至是秒級的,如果互動次數太多就會導致執行時間指數級的增加。不能把它當本地查詢一樣使用,使用時一定要仔細分析執行計劃。

相關文章