В версии 9i появилась функция coalesce которую называли обобщением NVL функции.
По сей день встречаются разработчики, которые никогда не слышали о ней, и уж тем более, не использовали. Чем больше я думал об приемуществах coaleasce, тем больше я считал возможным прекратить использовать NVL, и приобрести вместо этого привычку использовать coaleasce.
Первая причина - это большая динамичность. Мы можем определить первое не-NULL выражение в списке. Люди все время используют CASE, вместо coalesce.
CASE WHEN expr1 IS NOT NULL THEN expr1 ELSE expr2 END
Вторая причина, и более важная - Oracle использует вычисление короткого круга (short-circuit evaluation), по ANSI стандартам.
Иногда, когда мы сравниваем 2 значения, одно из них может быть дорого по оценке чтения значения, например если это запрос к таблице. В сценарии ниже я упростил это до наличия функции, которая спит некоторое указанное количество секунд.
10g> create or replace function sw_delay (pn_seconds number) return number is 2 begin 3 dbms_lock.sleep(pn_seconds); 4 return pn_seconds; 5 end; 6 / Function created. 10g> SET TIMING ON 10g> -- this will always delay 1 second 10g> select sw_delay(1) from dual; SW_DELAY(1) ----------- 1 1 row selected. Elapsed: 00:00:01.00 10g> 10g> -- While my function should never evaluate, the query still takes 1s 10g> select nvl(2, sw_delay(1)) from dual; NVL(2,SW_DELAY(1)) ------------------ 2 1 row selected. Elapsed: 00:00:01.00 10g> 10g> -- The same applies for nvl2 10g> select nvl2(1, 2, sw_delay(1)) from dual; NVL2(1,2,SW_DELAY(1)) --------------------- 2 1 row selected. Elapsed: 00:00:01.00 10g> 10g> -- The ANSI standard does not evaluate unnecessary expressions. 10g> select coalesce(2, sw_delay(1)) from dual; COALESCE(2,SW_DELAY(1)) ----------------------- 2 1 row selected. Elapsed: 00:00:00.00 10g> 10g> -- Decode is acceptable 10g> select decode(1,1,2,sw_delay(1)) from dual; DECODE(1,1,2,SW_DELAY(1)) ------------------------- 2 1 row selected. Elapsed: 00:00:00.01 10g> 10g> -- As is Case 10g> select case when 1 = 1 then 2 else sw_delay(1) end from dual; CASEWHEN1=1THEN2ELSESW_DELAY(1)END ---------------------------------- 2 1 row selected. Elapsed: 00:00:00.00 10g> select case 1 when 1 then 2 else sw_delay(1) end from dual; CASE1WHEN1THEN2ELSESW_DELAY(1)END --------------------------------- 2 1 row selected. Elapsed: 00:00:00.00Как показано выше, здесь не происходит вычисление второго выражения. Большинство программистов вначале помещают дешевые для вычисления выражения, чтобы сэкономить время работы процессора. Функции NVL и NVL2 не помогают в этом. А вот COALESCE, DECODE и оба CASE выражения вычисления короткого круга (short-circuit evaluation) - первейшее выражение вернувшее true, делает ненужным продолжение вычисление остальных выражений.
Другой способ продемонстрировать это:
10g> create or replace function sw_plsql (pn_seconds number) return varchar2 is 2 begin 3 if nvl(pn_seconds, sw_delay(1)) = 1 then 4 return 'do this'; 5 else 6 return 'do that'; 7 end if; 8 end; 9 / Function created. 10g> select sw_plsql(null) from dual; SW_PLSQL(NULL) ------------------------- do this 1 row selected. Elapsed: 00:00:01.00 10g> select sw_plsql(1) from dual; SW_PLSQL(1) ------------------------- do this 1 row selected. Elapsed: 00:00:01.00
Источник.
Комментариев нет:
Отправить комментарий