优化SQL查询

时间:2012-10-19 11:21:55

标签: sql query-optimization

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

 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

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

4 个答案:

答案 0 :(得分:2)

对于相同的标准,您正在对来自同一个表的4个结果进行联合,您是否可以只使用CASE语句? e.g。

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语句,但它将包含所有数据,并且将更容易阅读。性能也应该好很多。

答案 1 :(得分: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

的答案相同

你不需要第二个和第三个TOP 1,因为你只选择了所有联盟中的第一个

答案 2 :(得分: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

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

答案 3 :(得分:0)

我认为你应该根据需要制作Temp Table索引,然后从每个UNION中插入记录。 这比使用UNION s更快。