Начало » Использование СУБД » Firebird, HQbird, InterBase » Изменения оптимизатора?
Изменения оптимизатора? [сообщение #140] |
Tue, 05 July 2022 19:55 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
Есть такой запрос:
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where m.f0=?p0
and e.f1=?p1
and e.f2=?p2
and e.f3=?p3
and e.f4=?p4
На все поля, перечисленные в where, есть индексы (точнее, foreign keys, а индексы уже следствие).
Раньше FB использовал индекс по m.f0, и не мог использовать индексы по таблице e, потому что она была в left join. Теперь может, и это ломает планы. По полям f0 и f1 хорошая селективность, но оптимизатор использует не просто индекс по f1, а пересечение индексов по f1 и f2. Пересечение индексов наверное хорошая вешь для аналитических запросов, но для быстрых OLTP это просто беда, нужно всегда следить, чтобы такого не случилось.
В моём случае нужно переписать запрос как
where m.f0=?p0 and e.f1=?p1 and e.f2+0=?p2 and e.f3+0=?p3 and e.f4+0=?p4
Я думал, что это хорошая идея делать left join, чтобы исключить использование индексов (этот же трюк и в SQL Server работает). Теперь придётся видимо так делать:
left join Items_Ext e on e.Id=m.Id+0
Изменение произошло где-то между WI-V3.0.8.33392 и WI-V3.0.8.33540.
Это значит, при переезде с FB3 на FB4 может много чего полететь.
|
|
|
|
Re: Изменения оптимизатора? [сообщение #142 является ответом на сообщение #141] |
Tue, 05 July 2022 20:40 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
Пересечение индексов очень медленная операция.
Она оправдана, когда запрос возвращает миллионы строк.
Если запрос возвращает 1-2 строки, а нужно прочитать целиком пару индексов в огромных таблицах, это плюс 2-5 секунд к выполнению (против сотен миллисекунд при использовании одного индекса). Под нагрузкой супер-критично.
Впрочем, я проверил на более свежей версии WI-V3.0.10.33587 - вернули старое поведение.
Это был баг?
[Обновления: Tue, 05 July 2022 20:41] Известить модератора
|
|
|
|
Re: Изменения оптимизатора? [сообщение #151 является ответом на сообщение #148] |
Thu, 07 July 2022 15:00 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
m7m писал(а) Thu, 07 July 2022 08:07Это неверное утверждение/вывод, ну по крайней мере вторая часть "не мог использовать индексы по таблице e"
Ну я всегда использовал left join как hint оптимизатору "не использовать индексы на этой таблице" (кроме индекса по полю join, разумеется).
Можете на своих базах воспроизвести пример, когда индекс применяется в этом случае?
Вот мой пример: две огромные таблицы Items_Main и Items_Ext, параллельно связаны по полю Id.
В запросе
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where e.f1=?p1
Используется ужасно медленный план с полным сканом первой таблицы, хотя по индексу на второй таблице моментально выбралась бы ровно одна запись
PLAN JOIN (M NATURAL, E INDEX (PK_ITEMS_EXT))
[Обновления: Thu, 07 July 2022 15:02] Известить модератора
|
|
|
Re: Изменения оптимизатора? [сообщение #152 является ответом на сообщение #151] |
Fri, 08 July 2022 09:35 |
m7m
Сообщений: 18 Зарегистрирован: June 2022 Географическое положение: Мариуполь,Укр...
|
Junior Member |
|
|
>>Ну я всегда использовал left join как hint оптимизатору "не использовать индексы на этой таблице" (кроме индекса по полю join, разумеется).
>>Можете на своих базах воспроизвести пример, когда индекс применяется в этом случае?
Не могу, ибо именно про индексы по join я и имел ввиду
---------------
Блин я тебя не понимаю, откуда для запроса
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where e.f1=?p1
может появиться план
PLAN JOIN (M INDEX (.....), E INDEX (PK_ITEMS_EXT))
ты ж не накладываешь никаких ограничений на Items_Main m
Более того этот запрос, в данном случае эквивалентен запросу
select m.Id
from Items_Main m
join Items_Ext e on e.Id=m.Id
where e.f1=?p1
который будет наверное эффективней чем исходный
и план наверное будет где-то такой
PLAN JOIN (E INDEX (.....), M INDEX (.....))
или я вообще не понимаю, о чем речь
|
|
|
Re: Изменения оптимизатора? [сообщение #156 является ответом на сообщение #152] |
Fri, 08 July 2022 19:04 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
В WI-V3.0.8.33540 для запроса
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where m.f0=?p0
and e.f1=?p1
and e.f2=?p2
and e.f3=?p3
and e.f4=?p4
появился план примерно такой (пишу по памяти, версию уже обновили и доступа у меня к ней нет. могу где-то опечататься, но в целом так)
PLAN JOIN (E INDEX (FK_ITEMS_EXT_REF_F1, FK_ITEMS_EXT_REF_F2), M INDEX (PK_ITEMS_MAIN))
и это стало большой проблемой.
То есть, сервер никогда не использовал индексы по таблице, подключенной через left join, и вдруг начал.
[Обновления: Fri, 08 July 2022 19:16] Известить модератора
|
|
|
Re: Изменения оптимизатора? [сообщение #157 является ответом на сообщение #152] |
Fri, 08 July 2022 19:11 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
m7m писал(а) Fri, 08 July 2022 09:35
Более того этот запрос, в данном случае эквивалентен запросу ... который будет наверное эффективней чем исходный
и план наверное будет где-то такой
PLAN JOIN (E INDEX (.....), M INDEX (.....))
Да, эквивалентен, но оптимизатор не умеет его делать если таблица, по которой хороший индекс, приджойнена через left join.
Если считаете, что умеет, покажите тестовый скрипт (создать пару табличек, накидать пару тысяч записей и посмотреть план запроса) - у меня такое не выходит.
Если left join заменить на inner join - тогда да, оптимизатор начинает использовать хороший индекс по E.
|
|
|
Re: Изменения оптимизатора? [сообщение #158 является ответом на сообщение #156] |
Fri, 08 July 2022 22:31 |
m7m
Сообщений: 18 Зарегистрирован: June 2022 Географическое положение: Мариуполь,Укр...
|
Junior Member |
|
|
optimiz94 писал(а) Fri, 08 July 2022 19:04В WI-V3.0.8.33540 для запроса
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where m.f0=?p0
and e.f1=?p1
and e.f2=?p2
and e.f3=?p3
and e.f4=?p4
появился план примерно такой (пишу по памяти, версию уже обновили и доступа у меня к ней нет. могу где-то опечататься, но в целом так)
PLAN JOIN (E INDEX (FK_ITEMS_EXT_REF_F1, FK_ITEMS_EXT_REF_F2), M INDEX (PK_ITEMS_MAIN))
и это стало большой проблемой.
То есть, сервер никогда не использовал индексы по таблице, подключенной через left join, и вдруг начал.
Для этого запроса план более чем странный
|
|
|
Re: Изменения оптимизатора? [сообщение #159 является ответом на сообщение #157] |
Fri, 08 July 2022 22:43 |
m7m
Сообщений: 18 Зарегистрирован: June 2022 Географическое положение: Мариуполь,Укр...
|
Junior Member |
|
|
optimiz94 писал(а) Fri, 08 July 2022 19:11m7m писал(а) Fri, 08 July 2022 09:35
Более того этот запрос, в данном случае эквивалентен запросу ... который будет наверное эффективней чем исходный
и план наверное будет где-то такой
PLAN JOIN (E INDEX (.....), M INDEX (.....))
Да, эквивалентен, но оптимизатор не умеет его делать если таблица, по которой хороший индекс, приджойнена через left join.
Если считаете, что умеет, покажите тестовый скрипт (создать пару табличек, накидать пару тысяч записей и посмотреть план запроса) - у меня такое не выходит.
Если left join заменить на inner join - тогда да, оптимизатор начинает использовать хороший индекс по E.
Судя по тексту запроса
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where m.f0=?p0
and e.f1=?p1
and e.f2=?p2
and e.f3=?p3
and e.f4=?p4
тебе left join совершенно не нужен, и пожалуй даже вреден
и я не понимаю упорного желания его использовать ибо он по результатам совершенно эквивалентен запросу
select m.Id
from Items_Main m
join Items_Ext e on e.Id=m.Id
where m.f0=?p0
and e.f1=?p1
and e.f2=?p2
and e.f3=?p3
and e.f4=?p4
который дает волю оптимизатору построить оптимальный с его точки зрения план
И при этом если по каким-то причинам надо ограничить его свободу в использовании индексов
то заставить оптимизатор не использовать индекс можно как-то так e.f1+0=?p1
|
|
|
Re: Изменения оптимизатора? [сообщение #160 является ответом на сообщение #159] |
Sat, 09 July 2022 01:20 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
m7m, я не прошу помочь с написанием запроса.
Я здесь, чтобы обсудить факт - поведение оптимизатора существенно менялось, и возможно разработчики СУБД что-то скажут по этому поводу: это временный сбой был, или в будущих версиях они введут эту (в принципе, корректную) оптимизацию, и надо это иметь ввиду.
Также я зацепился за утверждение:
m7m писал(а) Thu, 07 July 2022 08:07>>Раньше FB использовал индекс по m.f0, и не мог использовать индексы по таблице e
Это неверное утверждение/вывод, ну по крайней мере вторая часть "не мог использовать индексы по таблице e" Если у вас такое на практике встречалось, прошу посмотреть - повторяется ли оно сейчас. Но я уже понимаю, что вы похоже просто теоретизировали.
|
|
|
Re: Изменения оптимизатора? [сообщение #161 является ответом на сообщение #160] |
Sat, 09 July 2022 07:22 |
m7m
Сообщений: 18 Зарегистрирован: June 2022 Географическое положение: Мариуполь,Укр...
|
Junior Member |
|
|
optimiz94 писал(а) Sat, 09 July 2022 01:20
Также я зацепился за утверждение:
m7m писал(а) Thu, 07 July 2022 08:07>>Раньше FB использовал индекс по m.f0, и не мог использовать индексы по таблице e
Это неверное утверждение/вывод, ну по крайней мере вторая часть "не мог использовать индексы по таблице e" Если у вас такое на практике встречалось, прошу посмотреть - повторяется ли оно сейчас. Но я уже понимаю, что вы похоже просто теоретизировали.
Я уже ответил на это:
>>Ну я всегда использовал left join как hint оптимизатору "не использовать индексы на этой таблице" (кроме индекса по полю join, разумеется).
>>Можете на своих базах воспроизвести пример, когда индекс применяется в этом случае?
Не могу, ибо именно про индексы по join я и имел ввиду
И таки да я теоретизировал, и продолжаю это делать
[Обновления: Sat, 09 July 2022 07:44] Известить модератора
|
|
|
Re: Изменения оптимизатора? [сообщение #162 является ответом на сообщение #160] |
Sat, 09 July 2022 07:38 |
m7m
Сообщений: 18 Зарегистрирован: June 2022 Географическое положение: Мариуполь,Укр...
|
Junior Member |
|
|
optimiz94 писал(а) Sat, 09 July 2022 01:20m7m, я не прошу помочь с написанием запроса.
Я здесь, чтобы обсудить факт - поведение оптимизатора существенно менялось, и возможно разработчики СУБД что-то скажут по этому поводу: это временный сбой был, или в будущих версиях они введут эту (в принципе, корректную) оптимизацию, и надо это иметь ввиду.
Да я и не помогаю, я для себя пытаюсь понять задлянафига такое делать.
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where m.f0=?p0
and e.f1=?p1
and e.f2=?p2
and e.f3=?p3
and e.f4=?p4
Сочетание left join и условие в where на ведомую таблицу в моей голове не укладывается
|
|
|
Re: Изменения оптимизатора? [сообщение #163 является ответом на сообщение #162] |
Sat, 09 July 2022 11:37 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
m7m писал(а) Sat, 09 July 2022 07:38Да я и не помогаю, я для себя пытаюсь понять задлянафига такое делать.
Сочетание left join и условие в where на ведомую таблицу в моей голове не укладывается
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where m.f0=?p0
and e.f1=?p1
and e.f2=?p2
and e.f3=?p3
and e.f4=?p4
В этой схеме данных такая специфика, что по полю f0 очень высокая селективность, во всей таблице M для любого значения выберется в пределах 10 строк (F0 это номер заказа), а по полям F1-F4 так себе селективность (это номенклатура). Поэтому я поставил left join, чтобы оптимизатор никогда не использовал индексы по E.
А тот запрос, который вызвал ваше недоумение
select m.Id
from Items_Main m
left join Items_Ext e on e.Id=m.Id
where e.f1=?p1
это попытка в чистом виде выделить проблему.
[Обновления: Sat, 09 July 2022 11:46] Известить модератора
|
|
|
|
Re: Изменения оптимизатора? [сообщение #182 является ответом на сообщение #166] |
Thu, 14 July 2022 11:17 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
Спасибо за ответ.
>> 1. Оптимизатор всегда мог использовать индексы полей в условии соединения left join
Я понимаю, что в операторе
left join e on e.Id = m.Id
используется индекс по e.Id
Вопрос этого топика в том, может ли в конструкции
left join e on e.Id = m.Id
where e.f1 = ?f1
использоваться индекс по e.f1
У меня ни на каких версиях не получалось
Кроме одной странной, с которой я начал топик - изменения в ней настораживают.
>> 2. Использовать left join как подсказку есть глупость
Понятно, но раньше отключение индексов хинтом 'left join' всегда работало.
Буду потихоньку переписывать на +0
>> Кстати есть наработки которые превращают такие left в inner join.
Видимо, я на такую наработку и нарвался.
Такое надо осторожно менять, потому что может много систем сломать в проде.
Кстати, есть ещё досадный баг с left join. В запросе
select *
from Items_Main m
join Items_Ext e on e.Id=m.Id
where e.F1 = ?f1
работает индекс по e.F1
А в запросе
select *
from Items_Main m
left join Users u on u.UserId=m.UserId
join Items_Ext e on e.Id=m.Id
where e.F1 = ?f1
индекс уже не работает, план
PLAN JOIN (JOIN (M NATURAL, U INDEX (PK_USERS)), E INDEX (PK_ITEMS_EXT))
А вот так - все в порядке
select *
from Items_Main m
join Items_Ext e on e.Id=m.Id
left join Users u on u.UserId=m.UserId
where e.F1 = ?f1
PLAN JOIN (JOIN (E INDEX (FK_ITEMS_EXT_REF_F1), M INDEX (PK_ITEMS_MAIN)), U INDEX (PK_USERS))
В автоматизированных конструкторах запросов, которые я сам пишу, я это учитываю, и все left join переставляю в конец. Геморой, но что поделать.
Но со всякими чужими ORM, которые сами создают запросы - беда.
Какие только извращения не приходится выдумывать, чтобы обойти этот баг.
>> И да "left join e ... where e. ..." вызывает недоумение
Зачем я так сделал, подробно написал в предыдущем посте: я полагался на то, что план будет построен вокруг индекса по m.F0, а условие по полю e.F1 будет обрабатываться не через индекс.
Сейчас переписал на +0 обращения к тем полям, по которым я не хочу использовать индекс.
[Обновления: Thu, 14 July 2022 11:35] Известить модератора
|
|
|
|
|
|
|
Re: Изменения оптимизатора? [сообщение #206 является ответом на сообщение #192] |
Tue, 19 July 2022 14:32 |
optimiz94
Сообщений: 15 Зарегистрирован: July 2022
|
Junior Member |
|
|
kdv писал(а) Mon, 18 July 2022 03:09не вижу ничего необычного в последних двух планах. left/right всегда выполняются строго "попарно". Поэтому оптимизатор сначала делает left, а потом делает inner. Если же вначале стоят inner, то у оптимизатора уже есть некая свобода действий.
А plan m natural потому что m left join, а дальше идет только условие объединения и фильтрация по e. Сервер никак тут не может использовать индексы по m, просто некуда. А left означает "взять все записи слева". Ну и ...
Но это какие-то внутренние заморочки движка. У MS SQL Server нет этой проблемы.
Вручную это всё можно учитывать и переставлять join-ы местами.
Но вот с ORM такой гибкости нет, приходится либо разбивать на несколько запросов, либо извращаться.
Например, на задачу "достань мне все заказы пользователей из Владивостока", ORM сделает запрос с планом (O NATURAL).
select ...
from Orders o
left join ... опциональные расширения к заказу в схеме данных
join Cities c on c.Id=o.CityId
where c.Id=?pCity
Приходится переформулировать как "достань мне город Владивосток и зафетчи его заказы"
dimitr писал(а) Mon, 18 July 2022 08:45По-моему, топикстартер забыл нам сказать, что у него не совсем Firebird... а на самом деле HQbird Думал, будет понятно из номеров версий публичных релизов.
[Обновления: Tue, 19 July 2022 15:24] Известить модератора
|
|
|
|
|
|
Переход к форуму:
Текущее время: Sun Dec 22 13:57:04 GMT+3 2024
Общее время, затраченное на создание страницы: 0.01994 секунд
|