2012-10-19 237 views
1

我有一个SQL查询,我想优化它作为SP的内部查询使用。优化SQL查询

SELECT TOP 1 @CurrentStartDate = Strt_Dt FROM (
SELECT 1 AS seq, Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID AND stat = 'INPR' 
    UNION 
    SELECT TOP 1 2 AS seq, Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID AND stat = 'CMPL' 
    ORDER BY enddate DESC 
    UNION 
    SELECT TOP 1 3 AS seq, Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID AND stat = 'PLND' 
    ORDER BY strt_dt 
    UNION 
    SELECT 4 AS seq, 'UNP', NULL, NULL, NULL, tckt_id, 'Unplanned' 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID 
) aa 
ORDER BY aa.seq 

有没有更好的方法来使用这个查询。我需要这个,因为我有很多相同类型的逻辑。

+0

应在第一个子查询中有一个ORDER'条款BY'?最后一个子查询是否应该有一个额外的'WHERE'子句,否则它似乎也包含前面查询中包含的所有记录?你能否展示一些数据来清楚表明什么是和未被使用这些“TOP 1”排除? – MatBailie

+0

*** SQL ***只是*结构化查询语言* - 许多数据库系统使用的语言,但不是数据库产品...优化是针对特定供应商的 - 因此我们真的需要知道**数据库系统**(以及您正在使用的版本).... –

+0

将简单英语添加到您想要实现的功能中也很有用 - 如果您解释它,则更容易帮助解决问题。查询应该做什么,它不做什么?性能问题有哪些? (我认为UNION是主要问题) – Charleh

回答

2

对于相同的条件,您正在对同一张表的4个结果进行联合,您是否可以不只是使用CASE语句?例如

SELECT 
    CASE Stat 
     WHEN 'INPR' THEN 1 
     WHEN 'CMPL' THEN 2 
     WHEN 'PLND' THEN 3 
     WHEN 'Unplanned' THEN 4 
     ELSE 0 -- Not sure what your 'ELSE' case would be 
    END as Seq, 
    etc.... 
FROM pipeline_rest_envr_info e 
WHERE e.tckt_id = @TicketID 

您仍然需要具有逻辑的所有字段的case语句,但它将包含所有数据,并且会更容易阅读。性能也应该更好。

+0

子查询一个没有ORDER BY,通过'end_dt'子查询两个订单,子查询'strt_dt'三个订单。这个答案没有考虑到这一点。然而,) – MatBailie

+0

同意 - 但我认为这是很难看到什么OP在与原始查询得到,所以我还不能确定这是否是我们所需要的 – Charleh

+0

我***认为,可以考虑一个解决方案** *如果有“进行中”记录,请返回它的开始日期。否则,返回上一个的开始日期以完成“已完成”记录。否则,返回下一个开始的“开始计划”记录。否则返回'NULL'。 – MatBailie

2
SELECT TOP 1 @CurrentStartDate = Strt_Dt FROM (
SELECT 
     CASE stat WHEN 'INPR' THEN 1 
        WHEN 'CMPL' THEN 2 
        WHEN 'PLND' THEN 3 
        ELSE 4 END AS seq , 
     Stat, Strt_Dt, Est_Hrs_Comp, EndDate, Tckt_Id, Envr 
    FROM pipeline_rest_envr_info e 
    WHERE e.tckt_id = @TicketID) aa 
ORDER BY aa.seq 

事实上它是相同的答案@Charleh

,因为你所有的工会

+1

子查询之一没有ORDER BY,通过'end_dt'子查询两个订单,通过'strt_dt'子查询三个订单。这个答案没有考虑到这一点。然而,) – MatBailie

+0

是的,谢谢,我没有看到'ORDER BY结束日期DESC'和'ORDER BY在这种情况下strt_dt'我认为你是最好的方法,这是很容易理解[这就是视图固体分] – Zyku

+0

你的意思是你认为OPs是最好的? *(我发表了评论,询问更多细节,但没有回答。)* – MatBailie

0

我想你应该有做只需要第一个你并不需要第二和第三TOP 1Temp Table这是你想要的索引,然后插入记录从每个UNION s。 这比使用UNION s更快一些。

2

我没有给我的意见作出答复,我会做出一些假设...

单个tckt_id可以有:

  • CMPL项目。 (完成?)
  • 只是一个INPR项目。 (进行中?)
  • 多个PLND项目。 (计划?)
  • 多个其他项目。 (计划外?)


你想要的strt_dt ...

  • INPR项目,如果它存在。
  • 否则,最后CMPL项,如果存在。
  • 否则,第一个PLND项目,如果存在。
  • 否则,NULL


SELECT 
    TOP 1 
    @current_start_date 
    = 
    CASE WHEN stat = 'INPR' THEN MIN(strt_dt) 
     WHEN stat = 'CMPL' THEN MAX(strt_dt) 
     WHEN stat = 'PLND' THEN MIN(strt_dt) 
          ELSE NULL 
    END 
FROM 
    pipeline_rest_envr_info 
WHERE 
    tckt_id = @TicketID 
GROUP BY 
    stat 
ORDER BY 
    CASE WHEN stat = 'INPR' THEN 1 
     WHEN stat = 'CMPL' THEN 2 
     WHEN stat = 'PLND' THEN 3 
          ELSE 4 END 


这确实有一个额外的假设:

  • 无论CMPL项目终于完成,也开始了最后

如果假设是错误的,如果你有ROW_NUMBER()访问,你可以试试这个,而不是...

WITH 
    plus_sort_order 
(
    SELECT 
    ROW_NUMBER() OVER (PARTITION BY stat ORDER BY strt_dt ASC) AS order_strt, 
    ROW_NUMBER() OVER (PARTITION BY stat ORDER BY end_dt DESC) AS order_end, 
    * 
    FROM 
    pipeline_rest_envr_info 
    WHERE 
    tckt_id = @TicketID 
) 
SELECT 
    TOP 1 
    @current_start_date = strt_dt 
FROM 
    plus_sort_order 
WHERE 
    (order_strt = 1) OR (stat = 'CMPL' AND order_end = 1) 
ORDER BY 
    CASE WHEN stat = 'INPR' THEN 1 
     WHEN stat = 'CMPL' THEN 2 
     WHEN stat = 'PLND' THEN 3 
          ELSE 4 END 

有相当多的其他方式。但很多取决于你的数据。我建议你在这里和其他答案中使用这些想法,并使用解释/查询计划来确定每个可用选项需要的索引。