在左连接查询的where子句中指定右表列时的性能问题

时间:2018-03-20 14:35:42

标签: sql-server performance sql-server-2016

请帮我重新设计以下查询以改善效果 -

select
    LT.id,
    LT.SalesAmount,
    RT.DiscountAmount,
    (LT.SalesAmount - isnull(RT.DiscountAmount,0.00)) as FinalAmount
from @LeftTable as LT
left join @RightTable as RT on RT.id = LT.id
where (LT.SalesAmount - isnull(RT.DiscountAmount,0.00)) > 0

注意 - 上面的查询并不完全是那个创建性能问题的查询,但我简化了它以便在这里更好地解释它。

我发现问题是,当我们在带有右表列的where子句中使用ISNULL时,即isnull(RT.DiscountAmount,0.00)。 所以,我正在寻找替代上述查询,我​​们可以从where子句中删除isnull

输入数据 -

declare @LeftTable table (id int, SalesAmount decimal(10,2))
declare @RightTable table (id int, DiscountAmount decimal(10,2))

insert into @LeftTable (id, SalesAmount)
select 1, 10.00
union all
select 2, 20.00
union all
select 3, 50.00

insert into @RightTable (id, DiscountAmount)
select 3, 5.00
union all
select 5, 10.00

需要输出 -

id  SalesAmount DiscountAmount  FinalAmount
1   10.00       NULL            10.00
2   20.00       NULL            20.00
3   50.00       5.00            45.00

实际查询类似于 -

select
    col1, col2,.....
from Table1 T1
inner join Table2 T2 on T2.id = T1.id
inner join dbo.functionName(@variable1) f1 on f1.id = T2.id
...................
left join (select col1, col2
    from table3 T3
    inner join dbo.functionName(@variable2) f2 on f2.id = T3.id) T4
    ......................
where
    T2.col1 + isnull(t4.col2, 0.0) > 0
    and .................

希望所以我在这里提到了所有细节,因为这就是我所拥有的(实际上我的同事正面临这个问题而我正在努力帮助他)。

5 个答案:

答案 0 :(得分:1)

你可以尝试这样的东西,它会消除ISNULL函数,但它会引入类似UNION的行为。

(
(LT.SalesAmount > 0 AND RT.DiscountAmount IS NULL)
OR (LT.SalesAmount - RT.DiscountAmount > 0)
)

答案 1 :(得分:0)

这是一个简单的方法:

where (RT.DiscountAmount IS NOT NULL AND LT.SalesAmount - RT.DiscountAmount > 0)
OR 
(RT.DiscountAmount IS NULL AND LT.SalesAmount > 0)

答案 2 :(得分:0)

您可以尝试以下内容:

;WITH JoinResults AS
(
    SELECT
        LT.id,
        LT.SalesAmount,
        RT.DiscountAmount,
        LT.SalesAmount,
        RT.DiscountAmount,
        LT.SalesAmount - RT.DiscountAmount as FinalAmount
    FROM
        @LeftTable as LT
        left join @RightTable as RT on RT.id = LT.id
)
SELECT
    *
FROM
    JoinResults AS J
WHERE
    (J.DiscountAmount IS NULL AND J.SalesAmount > 0) OR 
    J.FinalAmount > 0

答案 3 :(得分:0)

尝试

declare @LeftTable  table (id int primary key, SalesAmount decimal(10,2));
declare @RightTable table (id int primary key, DiscountAmount decimal(10,2));

insert into @LeftTable (id, SalesAmount) values
       (1, 10.00)
     , (2, 20.00)
     , (3, 50.00);

insert into @RightTable (id, DiscountAmount) values
       (3, 5.00)
     , (2, 25.00)
     , (5, 10.00);

select lt.id, lt.SalesAmount, rt.DiscountAmount, lt.SalesAmount - isnull(rt.DiscountAmount, 0) as net
from @LeftTable lt 
left join @RightTable rt 
  on lt.id = rt.id
where (LT.SalesAmount - isnull(RT.DiscountAmount,0.00)) > 0; 

select lt.id, lt.SalesAmount, rt.DiscountAmount, lt.SalesAmount - rt.DiscountAmount as net
from @LeftTable lt 
join @RightTable rt 
  on lt.id = rt.id
where (LT.SalesAmount - RT.DiscountAmount) > 0  
union all
select lt.id, lt.SalesAmount, null, lt.SalesAmount as net
from @LeftTable lt 
left join @RightTable rt 
  on lt.id = rt.id
where LT.SalesAmount > 0  
  and rt.id is null;

答案 4 :(得分:0)

用变量表替换子查询并使用变量表来保存子查询数据可以提高性能。

这是我们的方法 -

declare @xyz table (col1 int, col2 int)

insert into @xyz (col1, col2)
select col1, col2
    from table3 T3
    inner join dbo.functionName(@variable2) f2 on f2.id = T3.id

select
    col1, col2,.....
from Table1 T1
inner join Table2 T2 on T2.id = T1.id
inner join dbo.functionName(@variable1) f1 on f1.id = T2.id
...................
left join @xyz T4
    ......................
where
    T2.col1 + isnull(t4.col2, 0.0) > 0
    and .................

感谢@Xedni的评论。