Оптимизация запросов хранимых процедур - PullRequest
1 голос
/ 21 декабря 2009

У меня есть следующий запрос, и он не работает точно так, как я хочу, и он действительно медленный, поэтому я подумал, что попросил бы помочь.

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 ]

3 голосов
/ 21 декабря 2009

Я видел много вопросов, которые становятся проблемами, которые утверждают: «Я должен держать отличное там, иначе я получу повторяющиеся строки». Это просто еще одна проблема в рамках существующей проблемы. Это не только очень плохо порезанная повязка, это на самом деле часть проблемы.

Вероятно, вы не используете GROUP BY правильно, если вам нужно форсировать DISTINCT. Нам также нужно больше информации с примерами данных. Мой совет - перестать смотреть на весь кусок кода и разбираться во всем этом. Мой совет: посмотрите на первый выбор и выясните, действительно ли вам нужно сгруппировать все эти поля.

Take it one piece at a time

@ Новичок Я также добавил комментарий:

@ Новичок, возьми по одному ВЫБОРУ за раз. Получить некоторые данные, проверить данные, если они выглядят хорошо, и следующий внутренний выбор. Проверьте данные, убедитесь, что GROUP BY выглядят хорошо, добавьте следующий SELECT. Продолжайте, пока это не выглядит хорошо.

2 голосов
/ 21 декабря 2009

Чаще всего SQL-запросы не медленны не потому, что они веские, а из-за схемы таблицы (размер, количество элементов, селективность, доступные индексы). Оптимизатор может многое понять из запроса и оптимизировать его, независимо от того, насколько жестко он написан. Чтобы ответить на любой вопрос о производительности SQL-запроса, необходимо указать схему данных и размер таблиц.

Движок уже предоставляет вам большую помощь, чтобы ответить на ваш собственный вопрос. Он дает информацию о отсутствующих индексах , отслеживает индивидуальную производительность запросов , а документация охватывает основные рекомендации .

Я предлагаю вам начать с Учебник. Помощник по настройке ядра СУБД .

1 голос
/ 21 декабря 2009

Первым шагом в оптимизации является разделение запроса на маленькие части. Запустите каждую часть как шаг и определите, какая часть причиняет боль больше всего. Параметр «Показать фактический план выполнения» в меню «Запрос» может помочь в этом.

После того, как вы нашли часть запроса, которая причиняет боль, часто легко увидеть, как ее можно улучшить. Если вы не можете понять это, даже после попытки, вы можете опубликовать в переполнении стека с просьбой определенный совет.

0 голосов
/ 21 декабря 2009

Давайте посмотрим на это:

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_ADR является tinyint с значением по умолчанию 0 и ограничением (0,1)

Вы могли бы сначала (в подзапросе или cte) просто сказать:

sum(INV_ADR) AS [NumberOfInvalidAddr]

Затем в другом запросе, когда все агрегации выполнены, ссылаясь на первый:

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

Должно быть намного быстрее.

...