Индексирование нулевых значений в PostgreSQL - PullRequest
22 голосов
/ 12 августа 2010

У меня есть запрос вида:

select m.id from mytable m
left outer join othertable o on o.m_id = m.id
    and o.col1 is not null and o.col2 is not null and o.col3 is not null
where o.id is null

Запрос возвращает несколько сотен записей, хотя в таблицах миллионы строк, и на его выполнение уходит вечность (около часа).

Когда я проверяю статистику своего индекса, используя:

select * from pg_stat_all_indexes
where schemaname <> 'pg_catalog' and (indexrelname like 'othertable_%' or indexrelname like 'mytable_%')

Я вижу, что используется только индекс для othertable.m_id, и что индексы для col1..3 вообще не используются. Почему это?

Я прочитал в нескольких местах , что PG традиционно не может индексировать значения NULL. Тем не менее, я читал, что это предположительно изменилось с PG 8.3? В настоящее время я использую PostgreSQL 8.4 в Ubuntu 10.04. Нужно ли создавать «частичный» или «функциональный» индекс специально для ускорения запросов IS NOT NULL или он уже индексирует NULL, и я просто неправильно понимаю проблему?

Ответы [ 5 ]

30 голосов
/ 12 августа 2010

Вы можете попробовать частичный индекс:

CREATE INDEX idx_partial ON othertable (m_id)
WHERE (col1 is not null and col2 is not null and col3 is not null);

Из документов: http://www.postgresql.org/docs/current/interactive/indexes-partial.html

5 голосов
/ 12 августа 2010

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

CREATE INDEX findDaNulls ON othertable ((COALESCE(col1,col2,col3,'Empty')))
WHERE col1 IS NULL AND col2 IS NULL AND col3 IS NULL;

SELECT * 
FROM mytable m
JOIN othertable o ON m.id = o.m_id
WHERE COALESCE(col1,col2,col3,'Empty') = 'Empty';

Кстати, поиск нулевых левых соединений обычно не так быстр, как использование EXISTS или NOT EXISTS в Postgres.

1 голос
/ 12 августа 2010

A частичный индекс кажется правильным здесь:

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

Возможно, эти столбцы, которые могут содержать значения NULL (col1, col2, col3), действуют всценарий, как какой-то флаг, чтобы отличить некоторый подкласс записей в вашей таблице?(например, какое-то «логическое удаление»)?В этом случае, помимо решения с частичным индексом, вы можете переосмыслить свой дизайн и поместить их в разные физические таблицы (возможно, с использованием наследования), одну для «живых записей», другую для «исторических записей» и доступа к полному набору(только при необходимости) через вид.

1 голос
/ 12 августа 2010

Первой мыслью для этого запроса будет отдельный индекс для m_id, col1, col2 и o.col3.

И используйте EXPLAIN в этом запросе, чтобы увидеть, как он выполняется ичто занимает так много времени.Вы могли бы показать нам результаты, чтобы помочь вам.

0 голосов
/ 13 августа 2010

Вы пытались создать комбинированный индекс для других таблиц (m_id, col1, col2, col3)?

Вы должны также проверить план выполнения (используя EXPLAIN), а не проверять системные таблицы на предмет использования индекса.

PostgreSQL 9.0 (в настоящее время в бета-версии) сможет использовать и индексировать для условия IS NULL. Эта функция была отложена

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