Выделить функцию COALESCE? - PullRequest
1 голос
/ 16 января 2009

У меня большой запрос (не написанный мной, но я делаю некоторые изменения). Меня беспокоит то, что у меня одна и та же функция COALESCE примерно в четырех местах. Есть ли способ выделить это, возможно, с помощью выбора из DUAL? Есть ли какой-то выигрыш в производительности, если учесть это?

Вот запрос, слегка озадаченный:

select 
tbl1.gid
[snip]
         ,COALESCE(t1_end_dt, t6_actl_end_dt,t6_calc_end_dt) perd_end_dt
        ,t1_end_dt
FROM    tbl1
....
JOIN    tbl2               ON (t2_pk          = wpck_wrkr_id  AND
                                            t2_ind_1    ='Y'    AND
        COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt) 
        BETWEEN  t2_strt_dt AND t2_end_dt)
JOIN    tbl3                ON (t3_pk               = t2_fk_t3_pk AND
       COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt) 
        BETWEEN t3_strt_dt AND t3_end_dt)    
LEFT JOIN tbl4 tbl4_a             ON (tbl4_a.t4_pk         = chkw_wkt_id)
.....
GROUP BY tbl1.gid 
.....
        ,COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt)
        ,COALESCE(tbl4_b.t4_or_id, tbl4_a.t4_or_id, t7_or_id )
        ,t1_end_dt
ORDER BY perd_end_dt

Обратите внимание, что я уже выделил один из COALESCE, назвав его pred_end_dt в SELECT, а затем сослался на него по этому имени в ORDER BY.

Ответы [ 4 ]

2 голосов
/ 16 января 2009

Вы должны иметь возможность заменить вхождение в предложении GROUP BY на псевдоним вашего столбца perd_end_dt. Но вхождения в условиях JOIN не могут использовать псевдоним столбца.

Это влияет на производительность. Я не думаю, что присоединиться условия могут использовать индекс так, как они написаны в настоящее время. Тем не мение, это только один термин в состоянии JOIN, поэтому влияние может быть очень незначителен. То есть термины, включающие t2_pk и t2_ind_1, могут уже уменьшать набор строк, поэтому сравнение дат имеет дело только с небольшим набором. Это зависит от того, сколько строк мы говорим и как распределяются данные.

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

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


Другой вариант - определить псевдоним для выражения COALESCE(). в подзапросе. Я не могу сказать, из каких таблиц происходят столбцы, потому что вы не квалифицируете их псевдонимами таблиц. Но если я могу предположить, они все столбцы tbl1:

...
FROM (
    SELECT COALESCE(t1_end_dt, t6_actl_end_dt, t6_calc_end_dt) perd_end_dt,
      t1_fk_t2_pk
    FROM tbl1) t1
  JOIN tbl2
    ON (tbl2.t2_pk = t1.t1_fk_t2_pk AND tbl2.t2_ind_1 = 'Y'
      AND t1.perd_end_dt BETWEEN tbl2.t2_strt_dt AND tbl2.t2_end_dt)
...
1 голос
/ 16 января 2009

Есть ли у Oracle взгляды? (Так и должно быть.) Если вы обнаружите, что используете это выражение COALESCE() во многих разных местах, возможно, стоит создать VIEW и использовать его вместо исходных таблиц. Ниже будут выполнены те же вычисления, но синтаксис ваших запросов будет более кратким и, следовательно, более четким.

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

1 голос
/ 16 января 2009

Вы можете создать виртуальную таблицу

(Select Coalesce( all your stuff ....) perdEndDt 
   From [all your tables necessary for this one value])

и включите эту отдельную объединенную таблицу в ваш Select SQL

  Select [all yr other stuff,
      Z.perdEndDt
  From [Other Tables Joined together]
      Join 
         (Select Coalesce( all your stuff ....) perdEndDt,
               [other columns necessary for join conditions]
         From [all your tables necessary for this one value]) As Z
         On [Join conditions for Z to other tables]
  Where  [any filter predicates]
  Order By Z.perdEndDt
     ... etc.  
1 голос
/ 16 января 2009

Может быть, вы можете использовать предложение with?

with data as
(
   select COALESCE(t1_end_dt, t6_actl_end_dt,t6_calc_end_dt) perd_end_dt
   ,      .....
   ,      ...
   from   tbl1
)
select ...
from   data
,      ....
where  ....
...