2009-12-21 92 views
1

我有以下查询,它不是完全按照我想要的那样工作,而且它非常慢,所以我想我会寻求一些帮助。存储过程查询优化

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 [email protected] 
       AND [email protected]_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 [email protected] 
     AND [email protected]_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 [email protected] 
     AND [email protected]_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 

查询运行,如果我不这样做明显的最终选择,但我有点需要一个独特的,因为我有返回重复行。我猜这是因为图像领域。有没有更好/更有效的方式来进行这种性质的查询并返回正确数量的记录?

感谢

+0

这是很多代码需要通过 - 有人会真的想要代表经历理解所有这些过程。你有什么尝试?您是否检查了查询的执行计划,以开始获取有关缓慢的原因的线索? – 2009-12-21 17:47:15

+0

是的,我认为任何人都需要很长时间才能回答。也许我不应该一次性发布它。我并不是一个真正的sql人员。我该如何去研究执行计划?我应该寻找什么。 – Newbie 2009-12-21 17:57:03

+0

@Newbie一次只带一个SELECT。获取一些数据,检查数据,如果它看起来不错,接下来的内部选择。检查数据,确保GROUP BY看起来不错,然后添加下一个SELECT。继续前进,直到看起来不错。 – JonH 2009-12-21 18:02:53

回答

2

我见过很多问题,成为问题,说'我必须保持独特的地方,否则我会得到重复的行。'这只是现有问题中的另一个问题。这不仅是一个非常糟糕的切割绷带,它实际上是问题的一部分。

如果您不得不强制使用DISTINCT,那么您可能没有正确使用GROUP BY。我们还需要更多关于样本数据的信息。我的建议是停止查看整个代码片并全力以赴。我的建议是看第一个选择,并找出你是否真的需要在所有这些领域进行分组。

Take it one piece at a time 

@Newbie我还添加了评论:

@Newbie迈出了这一次选择。获取一些数据,检查数据,如果它看起来不错,接下来的内部选择。检查数据,确保GROUP BY看起来不错,然后添加下一个SELECT。继续前进,直到看起来不错。

2

最常见的SQL查询不慢,因为它们是如何wtitten,但由于表模式(规模,基数,选择性,可索引)的。优化程序可以从查询中理解很多内容,并对其进行优化,无论它的写法如何残酷。要回答有关SQL查询的任何性能问题,必须包括涉及的数据模式和表的大小。

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

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

+0

在这种情况下,我会说查询优化器根本不会帮助第一位的情况/总和疯狂。 – jfar 2009-12-21 18:06:40

1

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

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

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_ADR是一个char()试图伪造布尔值。现在,假设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 

应该更快。