Почему Postgres делает хэш в этом запросе? - PullRequest
3 голосов
/ 18 июня 2010

У меня есть две таблицы: A и P.Я хочу получить информацию из всех строк в A, чей идентификатор находится во временной таблице, которую я создал, tmp_ids.Однако в таблице P есть дополнительная информация о A, foo, и я тоже хочу получить эту информацию.У меня есть следующий запрос:

SELECT A.H_id AS hid,
       A.id AS aid,
       P.foo, A.pos, A.size
FROM tmp_ids, P, A
WHERE tmp_ids.id = A.H_id
  AND P.id = A.P_id

Я заметил, что это происходит медленно, и когда я попросил Postgres объяснить, я заметил, что он объединяет tmp_ids с индексом A, который я создал для H_idс вложенной петлей.Однако он хэширует все P перед выполнением хеш-соединения с результатом первого слияния.P довольно большой, и я думаю, что это занимает все время.Зачем это создает хэш там?P.id является первичным ключом P, а A.P_id имеет собственный индекс.

ОБНОВЛЕНИЕ: Все типы данных являются INTEGER, кроме A.size, который является ДВОЙНОЙ ТОЧНОСТЬЮ, и P.foo, который является VARCHAR.Я использую PostgreSQL версии 8.4.

Вот объяснение: http://explain.depesz.com/s/WBo.

Ответы [ 3 ]

3 голосов
/ 21 июня 2010

Планировщик запросов оценил, что было бы быстрее последовательно прочитать все данные и хэшировать их, чем выполнить примерно 2100 сканирований индекса с их гораздо более произвольным доступом к диску.

1 голос
/ 18 июня 2010

Не видя анализа объяснения, подобные проблемы обычно возникают из-за того, что статистика отключена или необычная настройка требуется для random_page_cost или seq_page_cost.

Это может работать лучше с

set enable_hashjoin = false;
0 голосов
/ 22 июня 2010

Ваша проблема в том, что оптимизатор не имеет правильной статистики, чтобы определить, сколько совпадений собирается создать «A.H_id = tmp_ids.id», что является распространенной проблемой для временных таблиц - они не имеют статистика, как обычная. Предполагается, что 21 строка будет соответствовать выходу из «сканирования индекса с использованием idx_A_handid на A», но на самом деле их только 3. Это выделено в анализе объяснения, где стрелка вверх самого низкого уровня имеет 7 рядом с ним, давая множитель за неправильную оценку.

Эта ошибка переносит туда, где, по ее мнению, у нее есть 2100 строк для сканирования, и в этот момент она может также выполнить полное последовательное сканирование и хэшировать результаты, учитывая, что это может коснуться большинства блоков таблицы.

Если бы он знал правильно, что было только 300 для исследования, он мог бы сделать что-то другое, включающее только подмножество данных. Вы не можете ожидать получения хороших планов от объединений с временными таблицами из-за отсутствия статистики. Это может быть тот случай, когда уместно подтолкнуть правильное поведение, отключив enable_hashjoin перед выполнением запроса.

...