Бага в сервере или моей голове. Прошу совета

arni
Дата: 29.07.2012 10:59:10
Есть очень ресурсоемкая процедура, вызывать ли которую через левое соединение внутри громадного запроса решается посредством переменной-флага. Оказалось, что она вызывается всегда, даже если флаг негативный. Минимальный пример, откуда выкинуто всё, а флаг заменен заведомо ложным условием:
select *
  from CUT_LOG c
  left join CALC_DOP_CUT_STAT(null, null, null, null) s on 0=0
 where 0=1
   and c.DAT_CUT='03.07.2012' --PLAN JOIN (C INDEX (IDX1_CUT_LOG), JOIN (Z INDEX (IDX2_ZAKAZ), T INDEX (PK_TMP_ZAKAZ)))
   --and c.DAT_CUT<>'03.07.2012' --PLAN JOIN (C NATURAL, JOIN (Z INDEX (IDX2_ZAKAZ), T INDEX (PK_TMP_ZAKAZ)))


CALC_DOP_CUT_STAT - процедура, тело которой сокращено до выброса исключения. Т.е. получение исключения - индикатор, что процедура вызвалась (чего бы мне не хотелось).

Итак, первая строка предиката (0=1) подразумевает, что ни одной строки из ведущей таблицы выбраться не должно, соответственно и левого соединения не должно быть. Так и происходит, если предикат ограничить только этим условием, либо если добавлена фильтрация, приводящая к натуралу (закомментированная строка снизу).

Если же есть фильтрация, вызывающая отбор по индексу (как в примере - отбор по полю-дате), то исключение ловим, - т.е. состоялась попытка осуществить левое соединение при наличии заведомо ложного предиката.

WI-V2.5.1.26351
arni
Дата: 29.07.2012 11:05:47
попробовал актуальный снепшот 26520 - тоже самое поведение.
Симонов Денис
Дата: 29.07.2012 11:08:30
К сожалению так было во всех версиях. Заведомо ложные условия вычисляются для каждой строки, а не один раз. Надеюсь в 3 ке исправят.
arni
Дата: 29.07.2012 11:12:18
PLAN JOIN (C INDEX (IDX1_CUT_LOG), CALC_DOP_CUT_STAT NATURAL)
PLAN JOIN (C NATURAL, CALC_DOP_CUT_STAT NATURAL)

закоментировал текст процедуры, кроме исключения и suspend, чтобы показать простые планы

Симонов Денис
К сожалению так было во всех версиях. Заведомо ложные условия вычисляются для каждой строки, а не один раз.
Не вижу, как кол-во вычилений условия может отменить тот факт, что оно всегда ложное
Симонов Денис
Дата: 29.07.2012 11:52:52
0=1 - вот это ложное вычисление
По идее оно должно быть вычислено один раз и соединение вообще должно ни разу не выполниться. Но на самом деле оно вычисляется для каждой строки уже после выполнения левого соединения
Симонов Денис
Дата: 29.07.2012 11:58:31
Думаю ситуация долна улучшиться если CUT_LOG c заменить на Devired Table с этим ложным условием
arni
Дата: 29.07.2012 12:19:31
Симонов Денис
Но на самом деле оно вычисляется для каждой строки уже после выполнения левого соединения
Даже боюсь себе представить, что все фильтрующие предикаты (котрые не по индексу), ужимают выборку только после того, как выполнятся все соединения. Прошлый опыт подсказывает, что это не так, иначе бы fb слыл бы тормозом из тормозов.
Послушаем, что скажут великие.


Симонов Денис
Думаю ситуация долна улучшиться если CUT_LOG c заменить на Devired Table с этим ложным условием
Пока просто передаю флаг в процедуру, и выхожу из неё сразу, если негативный.
Dimitry Sibiryakov
Дата: 29.07.2012 12:40:51

arni
Прошлый опыт подсказывает, что это не так

Опыт-шмопыт... Чтобы вычислить выражение нужно выбрать значения. Точка. Предвычислять
константные выражения Firebird не умеет. Это факт.

Posted via ActualForum NNTP Server 1.5

Симонов Денис
Дата: 29.07.2012 12:55:23
arni
Даже боюсь себе представить, что все фильтрующие предикаты (котрые не по индексу), ужимают выборку только после того, как выполнятся все соединения.


Не все конечно. Вот c.DAT_CUT='03.07.2012' это например выполниться раньше так как относится к ведущей таблице. Выражение же 1=0 относится только ко всему результату в целом.
arni
Дата: 29.07.2012 13:33:16
Симонов Денис,
Dimitry Sibiryakov,

спасибо. Два последних комментария вправили мозг.
Остается один вопрос: где тот тикет в трекере, где можно проголосовать за эту антифичу?
если конечно в 3.0 действительно не пофиксено уже ...