tl; др Вам необходимо добавить индекс на item_id
. «Черные маги c» индексации Postgres описаны в 11. Индексы .
У вас есть составной индекс на (topic_id, item_id)
, и порядок столбцов важен. Postgres может использовать это для индексации запросов на topic_id
, запросов на topic_id
и item_id
, но не (или менее эффективно) item_id
в одиночку.
С 11.3. Индексы с несколькими столбцами ...
Индекс B-дерева с несколькими столбцами можно использовать с условиями запроса, которые включают любое подмножество столбцов индекса, но индекс наиболее эффективен, когда существуют ограничения на ведущие (крайние левые) столбцы.
-- indexed
select *
from topics_items
where topic_id = ?
-- also indexed
select *
from topics_items
where topic_id = ?
and item_id = ?
-- probably not indexed
select *
from topics_items
where item_id = ?
Это связано с тем, что в составном индексе, например (topic_id, item_id)
, сначала хранится идентификатор topi c, а затем идентификаторы элементов, которые также имеют этот идентификатор topi c. , Чтобы эффективно найти идентификатор элемента в этом индексе, Postgres должен сначала сузить поиск с помощью идентификатора topi c.
Postgres может отменить Индекс, если он думает, что стоит усилий. Если имеется небольшое количество возможных идентификаторов topi c и большое количество возможных идентификаторов индекса, он будет искать идентификатор индекса в каждом topi c ID.
Например, предположим, что у вас есть 10 возможных идентификаторов topi c и 1000 возможных идентификаторов предметов и ваш индекс (topic_id, index_id)
. Это похоже на наличие 10 ячеек с идентифицированным топи c ID, каждый из которых содержит 1000 ячеек с идентифицированным идентификатором внутри. Чтобы попасть в корзины с идентификатором предмета, он должен заглянуть внутрь каждой корзины с идентификатором topi c. Чтобы использовать этот индекс для where item_id = 23
Postgres, необходимо выполнить поиск в каждом из 10 сегментов topi c ID для всех сегментов с идентификатором элемента 23.
Но если у вас есть 1000 возможных идентификаторов topi c и 10 возможных идентификаторов элементов, Postgres придется искать в 1000 корзинах topi c идентификаторов. Скорее всего, вместо этого будет выполнено полное сканирование таблицы. В этом случае вы захотите обратить свой индекс обратно и сделать его (item_id, topic_id)
.
Это в значительной степени зависит от наличия хорошей табличной статистики, что означает, что нужно убедиться, что автоочистка работает правильно.
Так что вы может обойтись одним индексом для двух столбцов, если один столбец имеет гораздо меньшую изменчивость, чем другой.
Postgres также может использовать множественные индексы, если считает, что запрос будет выполнен быстрее . Например, если у вас был индекс на topic_id
и индекс на item_id
, он может использовать оба индекса и объединить результаты. Например, where topic_id = 23 or item_id = 42
может использовать индекс topic_id для поиска topi c ID 23 и индекс item_id для поиска идентификатора элемента 42, а затем объединить результаты.
Это обычно медленнее, чем составной (topic_id, item_id)
индекс. Это также может быть медленнее, чем использование одного индекса, поэтому не удивляйтесь, если Postgres решит не использовать несколько индексов.
В общем, для индексов b-дерева, когда у вас есть два В столбцах у вас есть три возможных комбинации.
И вам нужно два индекса.
- (a, b) - a и a + b
- (b) - b
(a, b)
охватывает оба поиска a и a + б. (b)
охватывает поиск b
.
Если у вас есть три столбца, у вас есть семь возможных комбинаций.
- a + b + c
- a + b
- a + c
- a
- b + c
- b
- c
Но вам нужны только три индекса.
- (a, b, c) - a, a + b, a + b + c
- (б, c) - б, б + c
- (c, а) - c, c + а
Однако вы, вероятно, на самом деле хотите избежать индекса на три столбца. Это часто медленнее . То, что вы на самом деле хотите, это:
Многоколоночные индексы следует использовать с осторожностью. В большинстве случаев достаточно индекса для одного столбца, который экономит пространство и время. Индексы с более чем тремя столбцами вряд ли будут полезны, если использование таблицы не будет чрезвычайно стилизовано.
Чтение из индекса происходит медленнее, чем чтение из таблицы. Вы хотите, чтобы ваши индексы уменьшали количество строк, которые должны быть прочитаны, но вы не хотите, чтобы Postgres выполнял сканирование индекса больше, чем необходимо.
Ограничения на столбцы справа ... отмечены в индексе, поэтому они сохраняют посещения самой таблицы, но не уменьшают ту часть индекса, которая должна быть отсканирована. Например, если задан индекс для (a, b, c) и условие запроса WHERE a = 5 AND b> = 42 AND c <77, индекс должен быть отсканирован из первой записи с a = 5 и b = 42 до последней записи с a = 5. Записи индекса с c> = 77 будут пропущены, но их все равно придется сканировать.