【问题标题】:Optimize SQL query with aggregate function and case condition使用聚合函数和案例条件优化 SQL 查询
【发布时间】:2018-12-09 21:46:54
【问题描述】:

我想知道是否有更好的方法来编写这个 SQL。

CREATE TABLE #OrderTotals( [OrderID] uniqueIdentifier NULL, OrderTotal money 
NULL) 
CREATE NONCLUSTERED INDEX IDX_OrderTotals ON #OrderTotals(OrderID)

 Insert #OrderTotals (OrderID, OrderTotal)
    SELECT  o.Id,
    (CASE when o.OrderStatusId in (5,6,7) then  
    SUM(ISNULL(oi.[Price],0)* 
    ISNULL(oi.[InvoicedQty] ,0)+ ISNULL(oi.[TotalTax] ,0)) 

    When o.OrderStatusId not in (5,6,7) then
    SUM(ISNULL(oi.[Price],0)*(ISNULL(oi.[Quantity] ,0)
    - ISNULL(oi.[DeniedQuantity] ,0)) + ISNULL(oi. 
    [TotalTax] ,0)) end) as OrderTotal

    FROM orderItem oi
    inner join [Order] o on o.Id = oi.orderId
    WHERE  (o.Code = 'abc')
    group by o.id, o.OrderStatusId

我认为 CASE 对我的性能造成了影响,它使查询变慢。我在这里需要这个逻辑只是想知道是否有更好更有效的方法来编写它。

这是我的执行计划

【问题讨论】:

  • 样本数据和期望的结果真的很有帮助。
  • 所以有很多数据,比如大约 100K+。有些字段有 NULL,所以这就是为什么要检查 ISNULL。
  • 您需要一个聚集索引。我记得,如果在 SQL 2008 中没有它,您的表将非常低效。没有它,我相信服务器没有很好的方法来对磁盘上的数据进行排序,即使是暂时的。但这只是我的回忆。

标签: sql sql-server performance sql-server-2008


【解决方案1】:

首先,我会这样写查询:

select o.Id,
       (case when o.OrderStatusId in (5, 6, 7)
             then sum(coalesce(oi.Price * oi.InvoicedQty, 0) +
                      coalesce(oi.TotalTax, 0)
                     ) 
             else sum(coalesce(oi.Price * (oi.Quantity - coalesce(oi.DeniedQuantity, 0)), 0) +
                      coalesce(oi.TotalTax, 0)
                     ) 
        end)
from [Order] o join
     orderItem oi
     on o.Id = oi.orderId
where o.Code = 'abc'
group by o.id, o.OrderStatusId;

我认为它仍然有太多的coalesce() 调用,但您没有提供有关数据的足够信息。

为了优化这一点,您需要在 Order(Code, orderId)OrderItem(orderId) 上建立索引;

【讨论】:

  • hmm r u 建议 coalesce() 比 ISNULL() 快
  • 是的,索引确实有所作为,但影响不大。
  • 也许你只是有很多数据。
【解决方案2】:

case 什么时候应该是 SUM 的一部分。; ( SUM(case when .....)),

Insert #OrderTotals (OrderID, OrderTotal)
    SELECT  o.Id,
    SUM(
    CASE when o.OrderStatusId in (5,6,7) 
    then  
    ISNULL(oi.[Price]* oi.[InvoicedQty] ,0) + ISNULL(oi.[TotalTax] ,0)
ELSE
    ( ISNULL(oi.[Price] * oi.[Quantity] ,0) - ISNULL(oi.[DeniedQuantity] ,0) ) + ISNULL(oi.[TotalTax] ,0) 

     END) 
  as OrderTotal
FROM orderItem oi
    inner join [Order] o on o.Id = oi.orderId
    WHERE  (o.Code = 'abc')
    group by o.id, o.OrderStatusId

【讨论】:

    猜你喜欢
    • 2014-07-12
    • 1970-01-01
    • 1970-01-01
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-18
    相关资源
    最近更新 更多