存储过程查询优化

时间:2009-12-21 17:36:43

标签: sql-server stored-procedures query-optimization

我有以下查询,并且它不能完全按照我想要的方式工作,而且它非常慢,所以我想我会请求一些帮助。

CREATE PROCEDURE [dbo].[SummaryReport]
@event varchar(7) = null,
@pet_num varchar(12) = null
AS
BEGIN
WITH pet_counts
     AS (SELECT   event,
                  pet_num,
                  pageid,
                  linenum,
                  tot_sig_page,
                  IDNUM,
                  val_date,
                  obj_type
-- Objections
                  ,case when sum(case when INV_SIG = '1' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_SIG = '1' then 1 else 0 end)) + ' Invalid Sig' else '' end as InvalidSignature
      ,case when sum(case when INV_ADR = '1' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_ADR = '1' then 1 else 0 end)) + ' Invalid Addr' else '' end as InvalidAddress
      ,case when sum(case when INV_DIST = '1' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_DIST = '1' then 1 else 0 end)) + ' Invalid Dist' else '' end as InvalidDistrict
      ,case when sum(case when inc_adr = '1' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when inc_adr = '1' then 1 else 0 end)) + ' Inc Add' else '' end as IncAdd
      ,case when sum(case when dup_sig = '1' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when dup_sig = '1' then 1 else 0 end)) + ' Dup Sig' else '' end as DupSig
      ,case when sum(case when Inv_Circulator = '1' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when Inv_Circulator = '1' then 1 else 0 end)) + ' No CRC Date' else '' end as NoCRCDate
      ,case when sum(case when isnull(REASON,'') <> '' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when isnull(REASON,'') <> '' then 1 else 0 end)) + ' Other' else '' end as OtherReason
      ,sum(case when INV_SIG = '1' then 1 else 0 end)
     + sum(case when INV_ADR = '1' then 1 else 0 end)
     + sum(case when INV_DIST = '1' then 1 else 0 end)
     + sum(case when inc_adr = '1' then 1 else 0 end)
     + sum(case when dup_sig = '1' then 1 else 0 end)
     + sum(case when Inv_Circulator = '1' then 1 else 0 end)
     + sum(case when isnull(REASON,'') <> '' then 1 else 0 end) as TotalObjections
-- Sustained
      ,case when sum(case when INV_SIG_ST = 'S' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_SIG_ST = 'S' then 1 else 0 end)) + ' Sustained (Invalid Sig)' else '' end as SustainedInvalidSignature
      ,case when sum(case when INV_ADR_ST = 'S' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_ADR_st = 'S' then 1 else 0 end)) + ' Sustained (Invalid Addr)' else '' end as SustainedInvalidAddress
      ,case when sum(case when INV_DIST_ST = 'S' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_DIST_st = 'S' then 1 else 0 end)) + ' Sustained (Invalid Dist)' else '' end as SustainedInvalidDistrict
      ,case when sum(case when inc_adr_ST = 'S' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when inc_adr_st = 'S' then 1 else 0 end)) + ' Sustained (Inc Add)' else '' end as SustainedIncAdd
      ,case when sum(case when dup_sig_ST = 'S' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when dup_sig_st = 'S' then 1 else 0 end)) + ' Sustained (Dup Sig)' else '' end as SustainedDupSig
      ,case when sum(case when Inv_Circulator_ST = 'S' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when Inv_Circulator_ST = 'S' then 1 else 0 end)) + ' Sustained (No CRC Date)' else '' end as SustainedNoCRCDate
      ,case when sum(case when oth_reas_ST = 'S' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when oth_reas_st = 'S' then 1 else 0 end)) + ' Sustained (Other)' else '' end as SustainedOtherReason
      ,sum(case when INV_SIG_ST = 'S' then 1 else 0 end)
     + sum(case when INV_ADR_ST = 'S' then 1 else 0 end)
     + sum(case when INV_DIST_ST = 'S' then 1 else 0 end)
     + sum(case when inc_adr_ST = 'S' then 1 else 0 end)
     + sum(case when dup_sig_ST = 'S' then 1 else 0 end)
     + sum(case when Inv_Circulator_ST = 'S' then 1 else 0 end)
     + sum(case when oth_reas_ST = 'S' then 1 else 0 end) as TotalSustained
-- Overruled
      ,case when sum(case when INV_SIG_ST = 'O' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_SIG_ST = 'O' then 1 else 0 end)) + ' Overruled (Invalid Sig)' else '' end as OverruledInvalidSignature
      ,case when sum(case when INV_ADR_ST = 'O' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_ADR_st = 'O' then 1 else 0 end)) + ' Overruled (Invalid Addr)' else '' end as OverruledInvalidAddress
      ,case when sum(case when INV_DIST_ST = 'O' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when INV_DIST_st = 'O' then 1 else 0 end)) + ' Overruled (Invalid Dist)' else '' end as OverruledInvalidDistrict
      ,case when sum(case when inc_adr_ST = 'O' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when inc_adr_st = 'O' then 1 else 0 end)) + ' Overruled (Inc Add)' else '' end as OverruledIncAdd
      ,case when sum(case when dup_sig_ST = 'O' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when dup_sig_st = 'O' then 1 else 0 end)) + ' Overruled (Dup Sig)' else '' end as OverruledDupSig
      ,case when sum(case when Inv_Circulator_ST = 'O' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when Inv_Circulator_ST = 'O' then 1 else 0 end)) + ' Overruled (No CRC Date)' else '' end as OverruledNoCRCDate
      ,case when sum(case when oth_reas_ST = 'O' then 1 else 0 end) > 0 then convert(varchar(5), sum(case when oth_reas_st = 'O' then 1 else 0 end)) + ' Overruled (Other)' else '' end as OverruledOtherReason
      ,sum(case when INV_SIG_ST = 'O' then 1 else 0 end)
     + sum(case when INV_ADR_ST = 'O' then 1 else 0 end)
     + sum(case when INV_DIST_ST = 'O' then 1 else 0 end)
     + sum(case when inc_adr_ST = 'O' then 1 else 0 end)
     + sum(case when dup_sig_ST = 'O' then 1 else 0 end)
     + sum(case when Inv_Circulator_ST = 'O' then 1 else 0 end)
     + sum(case when oth_reas_ST = 'O' then 1 else 0 end) as TotalOverruled
-- Cand Exceptions
      ,sum(case when INV_SIG_EX = 'C' then 1 else 0 end)
     + sum(case when INV_ADR_EX = 'C' then 1 else 0 end)
     + sum(case when INV_DIST_EX = 'C' then 1 else 0 end)
     + sum(case when inc_adr_EX = 'C' then 1 else 0 end)
     + sum(case when dup_sig_EX = 'C' then 1 else 0 end)
     + sum(case when Inv_Circulator_EX= 'C' then 1 else 0 end)
     + sum(case when oth_reas_EX = 'C' then 1 else 0 end) as TotalCandidateExceptions
-- Objector Exceptions
      ,sum(case when INV_SIG_EX = 'O' then 1 else 0 end)
     + sum(case when INV_ADR_EX = 'O' then 1 else 0 end)
     + sum(case when INV_DIST_EX = 'O' then 1 else 0 end)
     + sum(case when inc_adr_EX = 'O' then 1 else 0 end)
     + sum(case when dup_sig_EX = 'O' then 1 else 0 end)
     + sum(case when Inv_Circulator_EX = 'O' then 1 else 0 end)
     + sum(case when oth_reas_EX = 'O' then 1 else 0 end) as TotalObjectorExceptions
        FROM petchl
        WHERE event=@event
              AND pet_num=@pet_num
        GROUP BY event,
                  pet_num,
                  pageid,
                  linenum,
                  tot_sig_page,
                  IDNUM,
                  val_date,
                 obj_type),
user_info as
(
 SELECT vp.IDNUM,
 v.full_name,
 ltrim((isnull(rtrim(ltrim(v.addr_num)),''))
 + ' ' + isnull(rtrim(ltrim(v.addr_frac)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_dir)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_str)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_type)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_other)),'')) as address1,
 (isnull(v.cityname,'')+ ' ' + isnull(v.addr_zip,'')) as address2,
 v.regdate,
 v.birthdate, 
 v.sex,
 v.prec,
 s.signature
FROM         petchl AS vp INNER JOIN
                      v_JPPUsers AS v ON vp.IDNUM = v.IDNUM LEFT OUTER JOIN
                      Signatures AS s ON v.IDNUM = s.IDNUM
WHERE    vp.event=@event
         AND vp.pet_num=@pet_num

UNION ALL
 SELECT vp.IDNUM,
 v.full_name,
 ltrim((isnull(rtrim(ltrim(v.addr_num)),''))
 + ' ' + isnull(rtrim(ltrim(v.addr_frac)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_dir)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_str)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_type)),'')
 + ' ' + isnull(rtrim(ltrim(v.addr_other)),'')) as address1,
 (isnull(v.cityname,'')+ ' ' + isnull(v.addr_zip,'')) as address2,
 null as regdate,
 v.birthdate, 
 v.sex,
 v.prec,
 s.signature
FROM         petchl AS vp INNER JOIN
                      v_Cityusers AS v ON vp.IDNUM = v.IDNUM LEFT OUTER JOIN
                      v_CitySignatures AS s ON v.IDNUM = s.IDNUM 
WHERE    vp.event=@event
         AND vp.pet_num=@pet_num
)

SELECT    p.event,
   p.PET_NUM,      
   p.PAGEID,       
   p.LINENUM,
         convert(varchar(10), vp.pet_date, 101) as pet_date,
   p.InvalidSignature,    
   p.InvalidAddress,
   p.InvalidDistrict,
   p.IncAdd,
   p.DupSig,
   p.NoCRCDate,
   p.OtherReason, 
   p.TotalObjections,   
   p.SustainedInvalidSignature,    
   p.SustainedInvalidAddress,
   p.SustainedInvalidDistrict,
   p.SustainedIncAdd,
   p.SustainedDupSig,
   p.SustainedNoCRCDate,
   p.SustainedOtherReason, 
   p.TotalSustained, 
   p.OverruledInvalidSignature,    
   p.OverruledInvalidAddress,
   p.OverruledInvalidDistrict,
   p.OverruledIncAdd,
   p.OverruledDupSig,
   p.OverruledNoCRCDate,
   p.OverruledOtherReason, 
   p.TotalOverruled,
   p.TotalCandidateExceptions,
   p.TotalObjectorExceptions,
   p.TOT_SIG_PAGE,  
   v.full_name,
   v.address1,
   v.address2,
   p.IDNUM,    
   v.regdate,
   v.birthdate, 
   convert(varbinary(max), v.signature) as signature
FROM     pet_counts p
         LEFT OUTER JOIN user_info v
           ON p.IDNUM = v.IDNUM
         LEFT OUTER JOIN vrpet vp
  ON p.event = vp.event 
           AND p.PET_NUM = vp.PET_NUM  
WHERE  p.event = @event
     and p.pet_num = @pet_num

ORDER BY pageid,
         linenum
END

如果我没有在最终选择上做一个明确的操作,那么查询就会运行,但是我需要一个明确的,因为我正在返回重复的行。我猜这是因为图像领域。有没有更好/更有效的方法来进行这种性质的查询并返回正确数量的记录?

由于

4 个答案:

答案 0 :(得分:3)

我已经看到许多问题成了问题,说'我必须保持不同,否则我会得到重复的行。'这只是现有问题中的另一个问题。它不仅是一个非常糟糕的绷带,它实际上是问题的一部分。

如果您不得不强制使用DISTINCT,则可能无法正确使用GROUP BY。我们还需要有关样本数据的更多信息。我的建议是停止查看整个代码片并将其全部搞清楚。我的建议是查看第一个选择,并确定你真的需要按所有这些字段进行分组。

Take it one piece at a time

@Newbie我还添加了评论:

@Newbie一次选择一个SELECT。获取一些数据,检查数据,看起来是否正常以及下一个内部选择。检查数据,确保GROUP BYs看起来不错,添加下一个SELECT。继续前进,直到看起来不错。

答案 1 :(得分:2)

大多数情况下,SQL查询并不慢,因为它们的重量级,但由于表模式(大小,基数,选择性,可用索引)。优化器可以从查询中理解很多,并且无论写得多么残酷,都可以对其进行优化。要回答有关SQL查询的任何性能问题,必须包括涉及的数据模式和表的大小。

引擎已经为您提供了很多帮助来回答您自己的问题。它提供了有关missing indexes的信息,它会跟踪个人query performance,文档涵盖basic recommendations

我建议你从Tutorial: Database Engine Tuning Advisor开始。

答案 2 :(得分:1)

优化的第一步是将查询分成小部分。将每个零件作为一个步骤运行,并确定哪个零件受伤最严重。查询菜单中的“显示实际执行计划”选项可以提供很大的帮助。

一旦您发现查询的部分受到伤害,通常很容易看出它是如何改进的。如果您无法弄清楚,即使在尝试之后,您也可以在Stack Overflow上发帖,询问具体的建议。

答案 3 :(得分:0)

让我们看看这个:

case 
when sum(case when INV_ADR = '1' then 1 else 0 end) > 0
then convert(varchar(5), sum(case when INV_ADR = '1' then 1 else 0 end)) + ' Invalid Addr'
else '' end as InvalidAddress

请注意,每行都会运行case(....)。有很多这样的人。

似乎INV_ADRchar()试图伪造布尔值。现在,假设 INV_ADRtinyint,默认为0,约束为(0,1)

您可以先(在子查询或cte中)简单地说:

sum(INV_ADR) AS [NumberOfInvalidAddr]

然后在另一个查询中 - 完成所有聚合后 - 引用第一个:

case 
when [NumberOfInvalidAddr] > 0
then convert(varchar(5), [NumberOfInvalidAddr]) + ' Invalid Addr'
else '' end as InvalidAddress

应该更快。