謹慎使用MyBatis自動生成Where語句


最近監控到類似這樣一個慢查詢:

select XX_time
from XXOrderInfo 
     WHERE (  OrderId is not null and
                   OrderId = N'xxxx') 
xxOrderInfo表上有一個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 XXXX_time
from XXOrderInfo 
     WHERE OrderId = 'xxxx'

執行計划當然也會是這樣的:

 

只是,只是不知道最終開發大神能改成什么樣......
---------------------------------------------------------------
開發大神的解決方案:連接字符串中配置:sendStringParametersAsUnicode=false
---------------------------------------------------------------
后記:

默認情況下,Java 中的字符數據作為 Unicode 進行處理;Java String 對象表示 Unicode 字符數據。在 JDBC 驅動程序中,唯一可以不遵守此規則的是 ASCII 流 getter 和 setter 方法,這屬於比較特殊的情況,因為這些方法使用的字節流帶有單個已知代碼頁 (ASCII) 的隱式假定。
此外,JDBC 驅動程序提供了 sendStringParametersAsUnicode 連接字符串屬性。此屬性可用於指定作為 ASCII 而不是 Unicode 來發送的字符數據的預定義參數。
作為性能方面的一項增強功能,可以通過設置 sendStringParametersAsUnicode 連接字符串屬性將 String 參數以非 Unicode 格式傳遞到 SQL Server。

如果 sendStringParametersAsUnicode 屬性設置為“true”,String 參數將以 Unicode 格式發送到服務器。
如果 sendStringParametersAsUnicode 屬性設置為“false”,String 參數將以非 Unicode 格式(如 ASCII/MBCS )而不是 Unicode 格式發送到服務器。
 sendStringParametersAsUnicode 屬性的默認值為“true”。 Note: 僅在使用 CHARVARCHAR 或 LONGVARCHAR JDBC 類型發送參數時檢查.sendStringParametersAsUnicode 屬性。 新的 JDBC 4.0 國家字符方法(例如 SQLServerPreparedStatement 和 SQLServerCallableStatement 類的 setNString、setNCharacterStream 和 setNClob 方法)始終將它們的參數值以 Unicode 格式發送到服務器,而不考慮此屬性的設置。

為了使 CHARVARCHAR 和 LONGVARCHAR JDBC 數據類型獲得最佳性能,應用程序應將 sendStringParametersAsUnicode 屬性設置為“false”並使用 SQLServerPreparedStatement 和 SQLServerCallableStatement 類的 setString、setCharacterStream 和 setClob 非國家字符方法。 當應用程序將 sendStringParametersAsUnicode 屬性設置為“false”並使用非國家字符方法訪問服務器端(如ncharnvarchar 和 ntext)上的 Unicode 數據類型時,如果數據庫排序規則不支持非國家字符方法傳遞的 String 參數中的字符,則某些數據可能丟失。 請注意,對於NCHARNVARCHAR 和 LONGNVARCHAR JDBC 數據類型,應用程序應使用 SQLServerPreparedStatement 和 SQLServerCallableStatement 類的 setNString、setNCharacterStream 和 setNClob 國家字符方法。

參考:

http://d.hatena.ne.jp/gnarl/20110706/1309945379

https://technet.microsoft.com/zh-cn/library/ms378857(SQL.110).aspx

https://technet.microsoft.com/zh-cn/library/ms378988(v=sql.110).aspx

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM