Начало » Использование СУБД » Firebird, HQbird, InterBase » coalesce() как реализована? (лишнего нам не надо)
coalesce() как реализована? [сообщение #3146] |
Wed, 20 September 2023 19:08 |
shalamyansky
Сообщений: 150 Зарегистрирован: August 2022
|
Senior Member |
|
|
coalesce( x, long_read() )
Можно представить 2 способа реализации, лобовой с предварительным вычислением аргументов
result = x;
y = long_read();
if( result is null ) then begin
result = y;
end
и оптимизированный без лишних действий
result = x;
if( result is null ) then begin
result = long_read();
end
Второй способ, ясен пень, требует от компилятора понимания, что он в случае coalesce() имеет дело не с обычной функцией, а по сути с некой особой языковой конструкцией. Но зато в некоторых случаях может существенно ускорить процесс исполнения, избежав никому не нужных вычислений.
Так как оно работает? Интересует прежде всего Firebird 4.0.
P.S.
Если же вычисления аргументов имеют еще и побочные эффекты, отличаться будет не только скорость, но и логика.
Предполагаю сам, что работает по первому варианту (с предварительными вычислениями). Но вдруг.
P.P.S.
Да, проверить экспериментально могу. Провоцирую на обсуждение. А как хотелось бы? А как правильно?
|
|
|
Re: coalesce() как реализована? [сообщение #3147 является ответом на сообщение #3146] |
Wed, 20 September 2023 19:32 |
shalamyansky
Сообщений: 150 Зарегистрирован: August 2022
|
Senior Member |
|
|
Мама миа! Все гораздо хуже! Вот что прочитал у Майкрософта про Transact-SQL:
Выражение COALESCE — синтаксический ярлык для выражения CASE. Это означает, что код COALESCE(expression1,...n) переписывается оптимизатором запросов как следующее выражение CASE:
CASE
WHEN (expression1 IS NOT NULL) THEN expression1
WHEN (expression2 IS NOT NULL) THEN expression2
...
ELSE expressionN
END
Поэтому входные значения (expression1, expression2, expressionN и т. д.) вычисляются многократно. Выражение значения, содержащее вложенный запрос, считается недетерминированным, и вложенный запрос вычисляется дважды. Этот результат соответствует стандарту SQL. В любом случае могут быть возвращены различные результаты для первого и последующих вычислений.
Например, если выполняется код COALESCE((subquery), 1), вложенный запрос вычисляется дважды. В результате можно получить различные результаты в зависимости от уровня изоляции запроса. Например, код может вернуть NULL при уровне изоляции READ COMMITTED в многопользовательской среде. Чтобы обеспечить устойчивые результаты, используйте уровень изоляции SNAPSHOT ISOLATION или замените COALESCE функцией ISNULL.
Кошмар... кошмар! Но это у них. А у нас?
|
|
|
|
Re: coalesce() как реализована? [сообщение #3149 является ответом на сообщение #3148] |
Wed, 20 September 2023 23:37 |
shalamyansky
Сообщений: 150 Зарегистрирован: August 2022
|
Senior Member |
|
|
Да, тоже проверил, работает по второму варианту. Тут уже главное, чтобы не по третьему, не как у Майкрософта. Но вычисления не дублируются, слава Firebird'у!
Майкрософт, однако, пишет, что они действуют по стандарту. Не очень, правда, понятно, по какому стандарту. Такой стандарт нам не нужен!
|
|
|
|
Re: coalesce() как реализована? [сообщение #3153 является ответом на сообщение #3146] |
Thu, 21 September 2023 15:19 |
shalamyansky
Сообщений: 150 Зарегистрирован: August 2022
|
Senior Member |
|
|
Так в том-то и дело, что в данном случае от реализации зависит результат. Если и не возвращаемое значение, то состояние системы в результате побочных эффектов может измениться по-разному. Вот, например
id = coalesce( x, gen_id() )
При реализации coalesce() по первому варианту счетчик генератора будет поднят в любом случае, а при реализации по второму варианту - только в случае x is null. И это может вызвать существенные последствия.
По факту наблюдаем, что конструкция coalesce() является не функцией, но особым оператором, вычисляющим операнды лишь по мере необходимости (причем единожды, не как у страшного MS). ИМХО этот факт достоин занесения если не в стандарт, то в описание языка Firebird (P)SQL уж точно.
P.S.
decode() и iif() тоже касается.
[Обновления: Thu, 21 September 2023 15:45] Известить модератора
|
|
|
|
Переход к форуму:
Текущее время: Sun Dec 22 17:43:32 GMT+3 2024
Общее время, затраченное на создание страницы: 0.00773 секунд
|