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
相关文章
相关标签/搜索