Postgresql - запрос выполняется намного быстрее с enable_nestloop = false.Почему планировщик не делает правильные вещи? - PullRequest
5 голосов
/ 25 октября 2011

У меня есть запрос, который выполняется намного медленнее (~ 5 минут), когда я запускаю его со значениями по умолчанию enable_nestloop = true и enable_nestloop = false (~ 10 секунд).

Объясните результаты анализа для обоих случаев:

Машина A nestloop = true - http://explain.depesz.com/s/nkj0 (~ 5 минут) Машина A nestloop = false - http://explain.depesz.com/s/wBM (~10 секунд)

На другом, немного более медленном компьютере, копирование базы данных и сохранение значения по умолчанию enable_nestloop = true занимает ~ 20 секунд.

Машина B nestloop = true - (~ 20 секунд)

Для всех вышеперечисленных случаев я обеспечил АНАЛИЗ перед выполнением запросов.Другие запросы не выполнялись параллельно.

На обеих машинах запущен Postgres 8.4.На компьютере A работает 32-разрядная версия Ubuntu 10.04, а на компьютере B работает 32-разрядная версия Ubuntu 8.04.

Фактический запрос доступен здесь.Это отчетный запрос со многими объединениями, так как база данных в основном используется для обработки транзакций.

  1. Не прибегая к чему-то вроде материализованных представлений, что я могу сделать, чтобы планировщик делал то, что ядостигается установкой enable_nestloop = false?

  2. Из проведенного мною исследования кажется, что причина, по которой планировщик выбирает, казалось бы, неоптимальный запрос, заключается в огромной разнице между оценочной ифактические строки.Как мне приблизить эту цифру?

  3. Если мне нужно переписать запрос, что я должен изменить?

  4. Почему планировщикКажется, что делает правильные вещи для машины B. Что я должен сравнивать на обеих машинах?

Ответы [ 4 ]

2 голосов
/ 29 декабря 2011

Это может быть полезно для чтения: Учебник по PostgreSQL о явных соединениях .

Планировщик запросов пытается проанализировать заказ JOIN, чтобы найти наилучший заказ для соединения.

Iувидел, что ваш запрос имеет по крайней мере 15 соединений.Количество возможных ордеров JOIN увеличивается как факториал (n!).Поэтому для планировщика запросов нецелесообразно пытаться найти лучший порядок JOIN, если имеется 15 JOIN - он должен смотреть на 15!= 1307674368000 разных планов.

Поэтому вместо него используется Genetic Query Optimizer.См. Планирование запроса: параметры генетического оптимизатора запросов .Параметр "geqo_threshold" определяет, сколько JOIN должно присутствовать, чтобы планировщик запросов использовал Genetic Query Optimizer.

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

Я думаю, что, как правило, если у вас так много таблиц для ПРИСОЕДИНЕНИЯ, вам лучше делать то, что вы делали: переписать запрос для оптимальногоПРИСОЕДИНИТЬСЯ к заказу.

2 голосов
/ 08 ноября 2011

Оказывается, переписывание запроса было лучшим решением. Запрос был написан так, что он в значительной степени опирался на левые соединения и имел много объединений. Я выровнял это и уменьшил количество левых объединений, используя свои знания о характере объединения данных в таблицах, к которым присоединялся запрос. Я полагаю, что эмпирическое правило заключается в том, что если планировщик выходит с реальными дерьмовыми оценками, возможно, существует лучший способ написания запроса.

2 голосов
/ 25 октября 2011

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

См. Эту Вики-страницу PostgreSQL по настройке сервера.Особое внимание обратите на главы random_page_cost и default_statistics_target .
Также прочтите соответствующие главы в руководстве по Статистика, используемая планировщиком и Константы стоимости планировщика .

Более конкретно, это может помочь увеличить statistics target для следующих столбцов:

ALTER TABLE postgres.products ALTER COLUMN id SET STATISTICS 1000;
ALTER TABLE postgres.sales_orders ALTER COLUMN retailer_id SET STATISTICS 1000;
ALTER TABLE postgres.sales_orders ALTER COLUMN company_id SET STATISTICS 1000;

ALTER TABLE goods_return_notes ALTER COLUMN retailer_id SET STATISTICS 1000;
ALTER TABLE goods_return_notes ALTER COLUMN company_id SET STATISTICS 1000;

ALTER TABLE retailer_category_leaf_nodes ALTER COLUMN tree_left SET STATISTICS 1000;
ALTER TABLE channels ALTER COLUMN principal_id SET STATISTICS 1000;

Они используются в фильтрах, в результате чего

огромная разница между оценочными и фактическими строками.

Есть больше .Проверьте каждый столбец, где строгальный станок сильно отклоняется от оценки.По умолчанию это просто 100. Имеет смысл только для таблиц с >> 1000 строк.Поэкспериментируйте с настройкой.Затем запустите ANALYZE для таблиц, чтобы изменения вступили в силу.

Может также помочь создать частичный индекс для postgres(sales_orders.retailer_id) WHERE retailer_id IS NOT NULL (в зависимости от того, насколько распространены значения NULL).


Еще одна вещь, которая может вам помочь, - обновить до последней версии 9.1.В этой области произошел ряд существенных улучшений.

0 голосов
/ 25 октября 2011

Обычно существует только одна причина для разного плана для одних и тех же данных и одинаковых запросов на двух серверах с одинаковым PostgreSQL.Это другая конфигурация - в основном значение work_mem.Хеш-соединение обычно быстрее, но требует много доступной памяти.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...