Запрос со многими операторами CASE — оптимизация

У меня есть один очень грязный запрос, который наверняка можно оптимизировать, потому что в нем так много операторов CASE!

SELECT 
    (CASE pa.KplusTable_Id WHEN 1 THEN sp.sp_id 
          WHEN 2 THEN fw.fw_id
          WHEN 3 THEN s.sw_Id
          WHEN 4 THEN id.ia_id END) as Deal_Id,
max(CASE pa.KplusTable_Id WHEN 1 THEN sp.Trans_Id 
                          WHEN 2 THEN fw.Trans_Id
                          WHEN 3 THEN s.Trans_Id
                          WHEN 4 THEN id.Trans_Id END) as TransId_CurrentMax
INTO #MaxRazlicitOdNull
FROM #PotencijalniAktuelni pa LEFT JOIN kplus_sp sp (nolock) on sp.sp_id=pa.Deal_Id AND pa.KplusTable_Id=1
    LEFT JOIN kplus_fw fw (nolock) on fw.fw_id=pa.Deal_Id AND pa.KplusTable_Id=2        
    LEFT JOIN dev_sw s (nolock) on s.sw_Id=pa.Deal_Id AND pa.KplusTable_Id=3
    LEFT JOIN kplus_ia id (nolock) on id.ia_id=pa.Deal_Id AND pa.KplusTable_Id=4
WHERE isnull(CASE pa.KplusTable_Id WHEN 1 THEN sp.BROJ_TIKETA 
                                   WHEN 2 THEN fw.BROJ_TIKETA
                                   WHEN 3 THEN s.tiket
                                   WHEN 4 THEN id.BROJ_TIKETA END, '')<>'' 
GROUP BY CASE pa.KplusTable_Id WHEN 1 THEN sp.sp_id 
                               WHEN 2 THEN fw.fw_id
                               WHEN 3 THEN s.sw_Id
                               WHEN 4 THEN id.ia_id END

Поскольку у меня пару раз было одно и то же условие, у вас есть идеи, как оптимизировать запрос, сделать его проще и лучше. Все предложения приветствуются!

TnX заранее!

Неманья


person Nemanja Vujacic    schedule 24.12.2010    source источник
comment
Не было бы проще иметь четыре простых оператора SELECT, по одному для каждого случая KplusTable_Id, а затем ОБЪЕДИНИТЬ их вместе?? Таким образом, вы можете забыть обо всем, что связано с CASE....   -  person marc_s    schedule 24.12.2010
comment
Я попробую с СОЮЗОМ. Может быть, у вас есть какие-то другие идеи, которые можно было бы использовать в этих ситуациях? Это похоже на распространенную проблему, которая, вероятно, имеет какую-то известную закономерность.   -  person Nemanja Vujacic    schedule 24.12.2010
comment
Похоже, это попытка создать структуру супертипа/подтипа, где pa.KplusTable_Id является дискриминатором типов. Можете ли вы подтвердить, что sp, fw, s, id являются подтипами pa? Например, если pa.Deal_Id = 1 and sp.sp_id = 1, есть ли запись в fw, s, id с _id = 1?   -  person Damir Sudarevic    schedule 24.12.2010
comment
@Damir Sudarevic - В этом случае могут быть fw_id=1, s_id=1 и ia_id=1, но это не будет одно и то же. Сделка уникальна в зависимости от Deal_Id и таблицы, на которой она размещена (в данном случае это может быть и KplusTable_Id). Я полагаю, что понял ваш вопрос, поэтому дал соответствующий ответ...   -  person Nemanja Vujacic    schedule 24.12.2010


Ответы (3)


Для меня это выглядит как неудачная попытка подтипа. Это то, что я думаю, что у вас есть сейчас.

альтернативный текст

На основе модели должно работать следующее:

;
with
q_00 as (
    select
         pa.Deal_Id                                                             as Deal_Id
       , coalesce(sp.BROJ_TIKETA, fw.BROJ_TIKETA, sw.tiket, ia.BROJ_TIKETA, '') as Ticket_No
       , coalesce(sp.Trans_Id, fw.Trans_Id, sw.Trans_Id, ia.Trans_Id)           as Trans_Id
    from #PotencijalniAktuelni as pa
    left join kplus_sp         as sp on sp.sp_Id = pa.Deal_Id and pa.KplusTable_Id = 1
    left join kplus_fw         as fw on fw.fw_Id = pa.Deal_Id and pa.KplusTable_Id = 2        
    left join dev_sw           as sw on sw.sw_Id = pa.Deal_Id and pa.KplusTable_Id = 3
    left join kplus_ia         as ia on ia.ia_Id = pa.Deal_Id and pa.KplusTable_Id = 4
)
select
      Deal_Id
    , max(Trans_Id) as TransId_CurrentMax
into #MaxRazlicitOdNull
from  q_00
where Ticket_No <> ''
group by Deal_Id ;

SQL Server 2005+

person Damir Sudarevic    schedule 24.12.2010
comment
Как сказал renegm (и у меня были некоторые чтения в то же время), UNION может быть очень «дорогой» операцией (особенно когда есть таблицы с большим количеством данных), поэтому я считаю, что это решение с LEFT JOIN-s и COALESCE очень хорошо . Спасибо Дамир! - person Nemanja Vujacic; 25.12.2010

Самый быстрый запрос может состоять в том, чтобы объединить каждое из 4 предложений и объединить их вместе. Код получается длиннее, но гораздо понятнее, что делает каждый блок, особенно если вы прокомментируете их вместе.

-- When KplusTable_Id  = 1
Select 
 sp.sp_id as as Deal_Id,
max(sp.Trans_Id) as TransId_CurrentMax
FROM #PotencijalniAktuelni pa LEFT JOIN kplus_sp sp (nolock) on sp.sp_id=pa.Deal_Id AND pa.KplusTable_Id=1
    LEFT JOIN kplus_fw fw (nolock) on fw.fw_id=pa.Deal_Id AND pa.KplusTable_Id=2        
    LEFT JOIN dev_sw s (nolock) on s.sw_Id=pa.Deal_Id AND pa.KplusTable_Id=3
    LEFT JOIN kplus_ia id (nolock) on id.ia_id=pa.Deal_Id AND pa.KplusTable_Id=4
WHERE sp.BROJ_TIKETA <>'' 
and pa.KplusTable_Id = 1
GROUP BY  sp.sp_id 

Union ...

-- When 2

Оберните весь запрос в выборку, чтобы выполнить вставку в #MaxRazlicitOdNull.

person u07ch    schedule 24.12.2010
comment
На самом деле, вы, вероятно, могли бы также уменьшить количество LEFT JOIN только до того, который соответствует вашим текущим критериям (KPlusTable_Id = 1 --> LEFT JOIN kplus_sp - все остальные здесь не имеют значения) - person marc_s; 24.12.2010
comment
@Doc Brown - Все таблицы kplus (включая dev_sw) имеют схожую структуру (вероятно, не будет полезно предоставлять все подробности о таблицах, поэтому я не буду тратить на это ваше время), данные хранятся (выбирая соответствующую таблицу) в зависимости от типа сделки. Временная таблица #PotencijalniAktuelni хранит данные, которые были предварительно отфильтрованы и состоят из Deal_Id, а также номера таблицы (которая будет использоваться в операторе CASE), а также пары других столбцов, которые не важны в этом примере. Пожалуйста, дайте мне знать, какая еще информация может быть полезна, и я постараюсь ее предоставить. - person Nemanja Vujacic; 24.12.2010

Чехлы мне подходят. Обычно быстрее, чем Union. Поместите несколько вариантов вашего запроса и сравните пакет в Plan. Только одна (незначительная) деталь Изменить

WHERE isnull(CASE pa.KplusTable_Id WHEN 1 THEN sp.BROJ_TIKETA 
                                   WHEN 2 THEN fw.BROJ_TIKETA
                                   WHEN 3 THEN s.tiket
                                   WHEN 4 THEN id.BROJ_TIKETA END, '')<>'' 

для этого

WHERE CASE pa.KplusTable_Id WHEN 1 THEN sp.BROJ_TIKETA 
                                   WHEN 2 THEN fw.BROJ_TIKETA
                                   WHEN 3 THEN s.tiket
                                   WHEN 4 THEN id.BROJ_TIKETA END is not null

Другой соль (с UNION):

SELECT  pa.Deal_Id, MAX(Q.Trans_Id) AS TransId_CurrentMax
INTO #MaxRazlicitOdNull
FROM 
(SELECT 1 A KplusTable_Id, Trans_Id, sp_id AS Deal_Id  FROM kplus_sp
UNION 
SELECT 2 AS KplusTable_Id, Trans_Id, fw_id AS Deal_Id FROM  kplus_fw  
UNION 
SELECT 3 AS KplusTable_Id, Trans_Id, sw_Id AS Deal_Id FROM  dev_sw
UNION 
SELECT 4 AS KplusTable_Id, Trans_Id, ia_id AS Deal_Id FROM kplus_ia) AS Q 
 INNER  JOIN #PotencijalniAktuelni pa ON pa.KplusTable_Id=Q.KplusTable_Id AND pa.Deal_Id=Q.Deal_Id
 GROUP BY pa.Deal_Id

Тестируйте каждый вариант запроса в плане и выбирайте быстрее

person renegm    schedule 24.12.2010
comment
Я видел, что практика в моей компании использует isnull(something, '')‹›''. Сначала для меня это был немного странный синтаксис, но позже я его принял. Знаете ли вы, есть ли какая-то важная разница между оператором at «не является нулевым»? - person Nemanja Vujacic; 25.12.2010
comment
Важные отличия? Зависит от того, как ты выглядишь. Одно отличие: сравнение против оценки+сравнения+сравнения. SQLServer оптимизирует это обычно, но не всегда. И в таких случаях, когда вам нужно знать, является ли строка нулевой, я предпочитаю нулевое значение для поиска заменителей. Заменители могут генерировать ошибку типа или использовать существующее значение. А про СОЮЗ. Union почти всегда будет медленнее, потому что одна и та же таблица сканируется более одного раза. Союз выглядит как алгоритм художника. Но это легко проверить: сложите оба варианта и спросите план. Союз стабильно более 50% затрат - person renegm; 25.12.2010
comment
Сегодня я сравнил эти два решения (UNION и LEFT JOIN-s) и не нашел большой разницы во времени выполнения. Причиной этого может быть то, что часть хранимой процедуры, включающая этот код, занимает всего 2% времени в плане выполнения, поэтому из-за этого разница не может быть очевидной. - person Nemanja Vujacic; 27.12.2010