postgres - медленный внешний запрос при использовании первичного ключа - PullRequest
1 голос
/ 19 ноября 2011

Использование Postgres v. 8.4.2.

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

SELECT b.id
   FROM scm_branch b
      LEFT OUTER JOIN "scm_branchgroup_branches" bgb
         ON b.id = bgb.branch_id
   WHERE
         bgb.branch_id is NULL
   LIMIT 1

(scm_branchgroup_branches - троичная таблица, в которой хранятся записи сопоставления)

этот запрос имеет следующую стоимость верхнего уровня:

Предел (стоимость = 0,00..0,22 строки = 1 ширина = 4)

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

SELECT b.id
   FROM scm_branch b
      LEFT OUTER JOIN "scm_branchgroup_branches" bgb
         ON b.id = bgb.branch_id
   WHERE
         bgb.id IS NULL 
   LIMIT 1

(примечание: этот запрос использует «bgb.id IS NULL» против «bgb.branch_id is NULL», использованного в предыдущем примере)

Стоимость верхнего уровня:

Предел (стоимость = 236366.74..4644900.75 строк = 1 ширина = 4)

Почему такая резкая разница? Я имею в виду, я вижу разницу в планах выполнения, но я не понимаю основных причин этой разницы.

Я буду рад предоставить любую дополнительную информацию, необходимую для ответа на этот вопрос.

Спасибо D.

1 Ответ

1 голос
/ 19 ноября 2011

В версии с branch_id IS NULL PostgreSQL распознает, что вы делаете анти-объединение, и соответственно оптимизирует его, используя алгоритм типа "hash-join". (Google PostgreSQL hash left anti-join для большого количества информации об этой оптимизации.) В версии с id IS NULL, однако, он не признает этот факт, и его оптимизации почти не так полезны. Более того, объединение в основном вынуждает его использовать индекс на branch_id, поэтому оно не может использовать преимущества индекса первичного ключа на id и должно просматривать фактические данные таблицы, чтобы определить, удовлетворяет ли данная запись ГДЕ-пункт.

(вполне могут быть и другие факторы - & mdash; я не специалист по PostgreSQL & mdash; но я считаю, что это основные факторы.)

...