Возможно, это поможет написать:
SELECT person FROM PhonesPersons WHERE phone < '+33 1234567'
UNION ALL
SELECT person FROM PhonesPersons WHERE phone > '+33 1234567'
или просто
SELECT person FROM PhonesPersons WHERE phone > '+33 1234567'
OR phone < '+33 1234567'
PostgreSQL должен быть в состоянии определить, что избирательность операции диапазона очень высока, и рассмотреть возможность использования индекса для него.
Я не думаю, что он может использовать индекс напрямую, чтобы удовлетворить предикат неравенства, хотя было бы неплохо, если бы он попытался переписать неравенство, как указано выше (если это помогает) во время планирования. Если это работает, предложите это разработчикам;)
Обоснование: поиск индекса по всем значениям, не равным определенному, требует сканирования полного индекса. В отличие от этого, поиск всех элементов, меньших определенного ключа, означает нахождение наибольшего несоответствующего элемента в дереве и сканирование назад. Аналогично, поиск всех элементов больше определенного ключа в обратном направлении. Эти операции легко выполнить с помощью структур b-дерева. Кроме того, статистика, которую собирает PostgreSQL, должна указывать на то, что «+33 1234567» является известным частым значением: удалив частоту этих значений и нулей из 1, мы получим пропорцию оставшихся строк: границы гистограммы укажите, перекошены ли они в одну сторону или нет. Но если исключение нулей и этого частого значения приводит к увеличению доли строк, оставшихся достаточно низкими (Istr около 20%), сканирование индекса должно быть уместным. Проверьте статистику для столбца в pg_stats, чтобы увидеть, какая пропорция фактически рассчитана.
Обновление : я пробовал это на локальной таблице с неопределенно похожим распределением, и обе формы выше дали что-то отличное от простого сканирования seq. Последнее (с использованием «ИЛИ») было растровым сканированием, которое может фактически превратиться в просто последовательное сканирование, если смещение к вашему общему значению особенно велико ... хотя планировщик может это увидеть, я не думаю, что он будет автоматически внутренне переписать в «Добавить (сканирование индекса, сканирование индекса)». Отключение «enable_bitmapscan» просто вернуло его к последующему сканированию.
PS : индексация текстового столбца и использование операторов неравенства могут быть проблемой, если ваша база данных не C. Это может потребоваться добавить дополнительный индекс, который использует text_pattern_ops или varchar_pattern_ops; это похоже на проблему индексации для предикатов column LIKE 'prefix%'
.
Альтернатива : вы можете создать частичный индекс:
CREATE INDEX PhonesPersonsOthers ON PhonesPersons(phone) WHERE phone <> '+33 1234567'
это сделает оператор выбора, использующий <>
, просто просканирует этот частичный индекс: поскольку он исключает большинство записей в таблице, он должен быть небольшим.