tl;dr Você precisa adicionar um índice em
item_id
. A "magia negra" da indexação do Postgres é abordada em 11. Índices
. Você tem um índice composto em
(topic_id, item_id)
e a ordem das colunas é importante. O Postgres pode usar isso para indexar consultas em topic_id
, consultas em ambos topic_id
e item_id
, mas não (ou menos eficientemente) item_id
sozinho. De 11.3. Índices de várias colunas ...
-- 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 = ?
Isso ocorre porque um índice composto como
(topic_id, item_id)
armazena primeiro o ID do tópico e, em seguida, os IDs de item que também possuem esse ID do tópico. Para pesquisar um ID de item com eficiência nesse índice, o Postgres deve primeiro restringir a pesquisa com um ID de tópico. Postgres pode reverter um índice se achar que vale a pena o esforço. Se houver um pequeno número de IDs de tópico possíveis e um grande número de IDs de índice possíveis, ele procurará o ID de índice em cada ID de tópico.
Por exemplo, digamos que você tenha 10 IDs de tópicos possíveis e 1.000 IDs de itens possíveis e seu índice
(topic_id, index_id)
. Isso é como ter 10 buckets de ID de tópico claramente rotulados, cada um com 1.000 buckets de ID de item claramente rotulados dentro. Para acessar os buckets de ID de item, ele deve procurar dentro de cada bucket de ID de tópico. Para usar este índice em where item_id = 23
O Postgres deve pesquisar cada um dos 10 buckets de ID de tópico para todos os buckets com ID de item 23. Mas se você tiver 1.000 IDs de tópicos possíveis e 10 IDs de itens possíveis, o Postgres teria que pesquisar 1.000 buckets de IDs de tópicos. Provavelmente, ele fará uma verificação completa da tabela. Nesse caso, você deseja reverter seu índice e torná-lo
(item_id, topic_id)
. Isso depende muito de ter boas estatísticas de tabela, o que significa garantir que o autovacuum esteja funcionando corretamente.
Assim, você pode se safar com um único índice para duas colunas, se uma coluna tiver muito menos variabilidade do que outra.
O Postgres também pode usar vários índices se achar que fará a consulta ser executada mais rápido . Por exemplo, se você tivesse um índice em
topic_id
e um índice em item_id
, ele pode use ambos os índices e combine os resultados. Por exemplo where topic_id = 23 or item_id = 42
poderia usar o índice topic_id para pesquisar o ID do tópico 23 e o índice item_id para pesquisar o ID do item 42 e, em seguida, combinar os resultados. Isso geralmente é mais lento do que ter um
(topic_id, item_id)
composto índice. Também pode ser mais lento do que usar um único índice, então não se surpreenda se o Postgres decidir não usar vários índices. Em geral, para índices b-tree, quando você tem duas colunas, você tem três combinações possíveis.
- a + b
- um
- b
E você precisa de dois índices.
- (a, b) -- a e a + b
- (b) -- b
(a, b)
abrange ambas as pesquisas para a e a + b. (b)
abrange a pesquisa de b
. Quando você tem três colunas, você tem sete combinações possíveis.
- a + b + c
- a + b
- a + c
- um
- b + c
- b
- c
Mas você só precisa de três índices.
- (a, b, c) -- a, a + b, a + b + c
- (b, c) -- b, b + c
- (c, a) -- c, c + a
No entanto, você provavelmente deseja evitar ter um índice em três colunas. Geralmente é mais lento . O que você realmente quer é isso.
- (a, b)
- (b, c)
- (c, a)
A leitura de um índice é mais lenta do que a leitura da tabela. Você quer que seus índices reduzam o número de linhas que devem ser lidas, mas não quer que o Postgres tenha que fazer mais varredura de índice do que o necessário.