Индексирование состояния частичного индекса в Postgres

Sep 05 2020

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

CREATE INDEX orders_unbilled_index ON orders (order_nr)
WHERE billed is not true

чтобы быстро выполнить запрос типа

SELECT *
FROM orders
WHERE billed is not true AND order_nr > 1000000

Postgres, очевидно, хранит индекс, order_nrпостроенный на подмножестве ordersтаблицы, как это определено условным выражением billed is not true. Однако у меня есть пара вопросов по этому поводу:

  1. Сохраняет ли Postgres внутри другой индекс, billed is not trueчтобы быстро находить строки, связанные с частичным индексом?
  2. Если (1) не соответствует действительности, ускорит ли выполнение указанного выше запроса, если я сделаю отдельный индекс для billed is not true? (при условии большой таблицы и нескольких строк с billed is true)

РЕДАКТИРОВАТЬ: мой пример запроса на основе документации не самый лучший из-за того, что логические индексы используются редко , но, пожалуйста, рассмотрите мои вопросы в контексте любого условного выражения.

Ответы

2 LaurenzAlbe Sep 06 2020 at 12:08

Индекс в виде b-дерева можно рассматривать как упорядоченный список записей индекса, каждая из которых имеет указатель на строку в таблице.

В частичном индексе список просто меньше: есть только записи индекса для строк, которые соответствуют условию.

Если в вашем WHEREпредложении есть условие индекса , PostgreSQL знает, что он может использовать индекс, и ему не нужно проверять условие индекса, потому что оно будет выполнено автоматически.

Так:

  1. Нет, любая строка, найденная с помощью индекса, автоматически удовлетворяет условию индекса, поэтому использования индекса достаточно, чтобы убедиться, что оно выполнено.

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

    На самом деле все наоборот: частичный индекс вполне может быть использован для запросов, в которых есть только booleanстолбец в WHEREусловии, если есть несколько строк, удовлетворяющих условию.

TimBiegeleisen Sep 06 2020 at 04:39

Насколько я понимаю, Postgres просто создаст индекс, который можно использовать только для поиска записей, которые billedне соответствуют действительности. То есть результирующее B-дерево будет проиндексировано order_nr, но будет ссылаться на исходную таблицу только в billedслучае ложного.

Если вы продолжите читать документацию , сразу после того, что вы процитировали, вы найдете следующий запрос в качестве примера:

SELECT * FROM orders WHERE billed is not true AND amount > 5000.00;

Это тот случай, когда Postgres может даже использовать индекс, который вы определили в приведенном выше запросе. Он может использовать ваш индекс для удовлетворения этого запроса путем сканирования всего индекса. Если имеется относительно небольшое количество заказов, по которым еще не выставлен счет, сканирование индекса order_nrможет быть предпочтительнее, чем полное сканирование таблицы.

Итак, ответ на ваш вопрос №1 заключается в том, что нет, отдельного индекса для него нет billed, но индекс on order_nrможет использоваться только для записей, для которых billedустановлено значение false. А для № 2, да, можно использовать второй индекс, если счет за billed is not trueнесколько записей не выставлен. Однако даже ваш текущий индекс может использоваться как есть.