SQLRU.net
Разработка приложений баз данных

Начало » Использование СУБД » Firebird, HQbird, InterBase » coalesce() как реализована? (лишнего нам не надо)
coalesce() как реализована? [сообщение #3146] Wed, 20 September 2023 19:08 Переход к следующему сообщению
shalamyansky в настоящее время не в онлайне  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 в настоящее время не в онлайне  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() как реализована? [сообщение #3148 является ответом на сообщение #3146] Wed, 20 September 2023 19:41 Переход к предыдущему сообщениюПереход к следующему сообщению
shavluk в настоящее время не в онлайне  shavluk
Сообщений: 82
Зарегистрирован: June 2022
Географическое положение: Одеса
Member
Проверил, работает второй вариант.
Хотя я почему-то думал что будет первый, но так правильнее.
Мне кажется этот момент должен быть прописан в стандарте.
Re: coalesce() как реализована? [сообщение #3149 является ответом на сообщение #3148] Wed, 20 September 2023 23:37 Переход к предыдущему сообщениюПереход к следующему сообщению
shalamyansky в настоящее время не в онлайне  shalamyansky
Сообщений: 150
Зарегистрирован: August 2022
Senior Member
Да, тоже проверил, работает по второму варианту. Тут уже главное, чтобы не по третьему, не как у Майкрософта. Но вычисления не дублируются, слава Firebird'у!

Майкрософт, однако, пишет, что они действуют по стандарту. Не очень, правда, понятно, по какому стандарту. Такой стандарт нам не нужен!
Re: coalesce() как реализована? [сообщение #3150 является ответом на сообщение #3148] Thu, 21 September 2023 09:21 Переход к предыдущему сообщениюПереход к следующему сообщению
sim_84 в настоящее время не в онлайне  sim_84
Сообщений: 330
Зарегистрирован: June 2022
Senior Member
Стандарт ничего не говорит о последовательности вычислений, ленивости, кешировании результатов и т.д.
С точки зрения стандарта только конечный результат должен быть верен, а оптимизация лежит на реализаторе.
Re: coalesce() как реализована? [сообщение #3153 является ответом на сообщение #3146] Thu, 21 September 2023 15:19 Переход к предыдущему сообщениюПереход к следующему сообщению
shalamyansky в настоящее время не в онлайне  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]

Известить модератора

Re: coalesce() как реализована? [сообщение #3155 является ответом на сообщение #3153] Thu, 21 September 2023 16:59 Переход к предыдущему сообщению
МП в настоящее время не в онлайне  МП
Сообщений: 887
Зарегистрирован: August 2022
Географическое положение: бурятский тун...
Senior Member
так было не всегда.
смотри на предмет CompleteBooleanEvaluation.
Предыдущая тема: Ubuntu 22.04 Firebird 3.0 & Firebird 2.5
Следующая тема: isc_prepare_transaction() , isc_prepare_transaction2()
Переход к форуму:
  


Текущее время: Thu Nov 21 21:02:03 GMT+3 2024

Общее время, затраченное на создание страницы: 0.00698 секунд