SQL Server優化技巧——如何避免查詢條件OR引發的性能問題

以前寫過一篇博客SQL SERVER中關於OR會致使索引掃描或全表掃描的淺析,裏面介紹了OR可能會引發全表掃描或索引掃描的各類案例,以及如何優化查詢條件中含有OR的SQL語句的幾種方法,其實還有一些方法能夠用來優化這種問題,這裏簡單介紹一下。html

 

以下所示,下面的SQL語句之全部出現這種寫法,是由於程序的查詢界面,可能有多個輸入性的查詢條件,每每用戶只填了一個或部分查詢條件(業務狀況,應該不用詳細介紹,你們都能明白),可是程序裏面沒有經過判斷查詢條件生成不一樣的SQL語句,而是用一個SQL搞定,無論用戶沒有填寫JobNo這個查詢條件,下面這種寫法:WHERE ISNULL(@JobNo, '') = ''  OR JobNo = @JobNo都能知足條件,實現邏輯功能。app

 

DECLARE @GenerateDateStart DATETIME ,
    @GenerateDateEnd DATETIME ,
    @JobNo NVARCHAR(200) ,
    @GkNo NVARCHAR(200);
SET @JobNo = 'PT19B030';
SET @GkNo = 'PV19-1-8050'; 
 
  SELECT    *
  FROM      [dbo].[GEW_UnitConsumption] AS A
            LEFT JOIN dbo.UnitConsumption_Relation AS B ON B.UsableFlag = 'Y'
                                                           AND A.GewUnitConsumptionId = B.RootUnitConsumptionID
  WHERE     ( ISNULL(@JobNo, '') = ''
              OR A.JobNo = @JobNo
            )
            AND ( ISNULL(@GkNo, '') = ''
                  OR A.GkNo = @GkNo
                );

 

其實,若是根據查詢條件動態生成SQL語句,的確能避免查詢條件中出現OR的情形,可是動態SQL語句沒有上面語句簡單和通熟易懂,尤爲是查詢條件較多的狀況下。只能說各有利弊。這裏暫且不討論那種策略的優劣。性能

 

 

clip_image001

 

下面介紹一種技巧,如何避免OR引發的索引掃描或全表掃描問題。咱們可使用CASE WHEN改寫一下這個SQL語句,就能避免OR引發的執行計劃不走索引查找(Index Seek)的狀況,以下所示:測試

 

DECLARE @GenerateDateStart DATETIME ,
    @GenerateDateEnd DATETIME ,
    @JobNo NVARCHAR(200) ,
    @GkNo NVARCHAR(200);
SET @JobNo = 'PT19B030';
SET @GkNo = 'PV19-1-8050'; 
 
 
SELECT  *
FROM    [dbo].[GEW_UnitConsumption] AS A
        LEFT JOIN dbo.UnitConsumption_Relation AS B ON B.UsableFlag = 'Y'
                                                       AND A.GewUnitConsumptionId = B.RootUnitConsumptionID
WHERE   CASE WHEN ISNULL(@JobNo, '') = '' THEN A.JobNo
             ELSE @JobNo
        END = JobNo
        AND CASE WHEN ISNULL(@GkNo, '') = '' THEN A.GkNo
                 ELSE GkNo
            END = @GkNo;

 

clip_image002

 

測試對比發現性能改善很是明顯,固然這種優化技巧也是有侷限性的,並不能解決全部OR引發的性能問題(沒有銀彈!)。以下所示,對於下面這種狀況,這種技巧也是無能爲力!優化

 

 

SELECT * FROM TEST1 WHERE A=12 OR B=500
相關文章
相關標籤/搜索