PostgreSQL странный план выполнения
Есть приложение написанное на Java + Hibernate, база данных - PostgreSQL. Сейчас в базе данных присутствует 90 таблиц. Почти все таблицы пустые. В нескольких таблицах всего по 1-2 записи. Есть запрос на выборку 1280 полей, используется 91 join и в блоке where указано три условия:
where field1=3
and field2='OPEN'
and field3='ACTIVE';
результат выполнения: 0 rows retrieved in 1 s 760 ms (execution: 110 ms, fetching: 1 s 650 ms)
Но очень странно выглядит план выполнения:

Мне не понятно почему читается такое большое количество строк, если их столько нет в БД. С чем это может быть связано?
Ответы (1 шт):
Это вы смотрите в какой-то сторонней программе и тут не вполне ясно, что это за Rows.
Это поле, очевидно, показывает estimated rows т.е. оценка постгресом количества строк, которое вернет соответсвующий узел в плане.
Эта оценка даже при актуальной статистике не всегда верная и чем сложнее запрос, тем больше расхождение, т.к. ошибка в оценка накапливается (это видно - для вложенных узлов номральные числа).
В принципе это оценка считается приблизительно так. Для начального узла, который представляет собой какой-то поиск по таблице X1 (это может быть или полное сканирование таблицы или поиск по условию) планировщик на основе статистике делает оценку количества строк, которые будут возвращены в результате. Назовем ее C1.
Далее нужно посчитать оценку для количества строк при соединении к этой таблице другой X2 по некоторому условию. Тут планировщик опять же смотрит, какое среднее значение строк (A1) при поиске по этому условию будет возвращено для каждой записи из X1. Он берет это среднее и умножает на оценку количества строк из предыдущего шага, т.е. на C1. Получается C2 = C1 * A1.
И так он делает для каждого join-a. Учитывая, что все значения Ai - приблизительные, то во-первых, ошибка накапливается, а во-вторых, в вашем случае еще и очень быстро растет, так как у вас видно, что для многих узлов значение увеличивается в 1000 раз для каждого нового join-a (т.е. планировщик считает, что join для каждой записи найдет приблизительно 1000 записей из другой таблицы).
Обычная рекомендация по улучшению статистики (и плана) это настроить параметры сбора статистики (т.е. увеличить количество статистики, чтоб постгрес мог сохранять больше информации о распределении значений, и соответственно точнее оценивать количество строк при выборках). Но, подозреваю, что с 91 join-ом, никакое увеличение не поможет.