最近監控到類似這樣一個慢查詢: select delete_flag,delete_time from D_OrderInfo WHERE ( OrderId is not null and OrderId = N'xxxx') D_OrderInfo表上有一個OrderId的索引,但OrderId
最近監控到類似這樣一個慢查詢:
select delete_flag,delete_time from D_OrderInfo WHERE ( OrderId is not null and OrderId = N'xxxx')
D_OrderInfo表上有一個OrderId的索引,但OrderId欄位是Varchar類型。
由於開發框架MyBatis自動生成Where條件不會指定參數類型,字元串類型的參數到了SQLServer里就自動成了NVARCHAR(4000)類型了,
坑人的是,不指定參數類型也就罷了,還自動加了個OrderId Is NOT NULL這樣一個非SARG的條件,執行計劃成了這樣:
---------------------------------------------------------------------------------------------
如果沒有OrderId IS NOT NULL這個條件,執行計劃會是這樣的:
由於參數類型Nvarchar比索引欄位類型varchar優先順序要高,不能直接轉換,但SQLServer優化器最終還是將他轉成了一個範圍值,最終的等號查詢也變成了類似一個小範圍查詢。
可以從Index Seek這一步的詳細信息可以看出:
------------------------------------------------------------------------
如果參數類型匹配,那麼執行計劃會是想象中的那樣(雖然沒有包含到,還是有Key Lookup):
--------------------------------------------------------------------------------------
當然,有點小小強迫症的我最終希望的寫法是這樣的:
select delete_flag,delete_time from D_OrderInfo WHERE OrderId = 'xxxx'
執行計劃當然也會是這樣的:
只是,只是不知道最終開發大神能改成什麼樣......