PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Indicizzazione di chiavi esterne in Postgresql

tl;dr Devi aggiungere un indice su item_id . La "magia nera" dell'indicizzazione di Postgres è trattata in 11. Indici .

Hai un indice composito su (topic_id, item_id) e l'ordine delle colonne è importante. Postgres può usarlo per indicizzare le query su topic_id , query su entrambi topic_id e item_id , ma non (o meno efficientemente) item_id da solo.

Da 11.3. Indici a più colonne ...

-- 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 = ?

Questo perché un indice composito come (topic_id, item_id) memorizza prima l'ID argomento, quindi gli ID elemento che hanno anche quell'ID argomento. Per cercare un ID elemento in modo efficiente in questo indice, Postgres deve prima restringere la ricerca con un ID argomento.

Postgres può invertire un indice se pensa che ne valga la pena. Se è presente un numero ridotto di possibili ID argomento e un numero elevato di possibili ID indice, cercherà l'ID indice in ciascun ID argomento.

Ad esempio, supponiamo che tu abbia 10 possibili ID argomento e 1000 possibili ID elemento e il tuo indice (topic_id, index_id) . È come avere 10 bucket ID argomento chiaramente etichettati, ciascuno con 1000 bucket ID articolo chiaramente etichettati all'interno. Per accedere ai bucket ID elemento, è necessario cercare all'interno di ciascun bucket ID argomento. Per utilizzare questo indice su where item_id = 23 Postgres deve cercare in ciascuno dei 10 bucket di ID argomento tutti i bucket con ID elemento 23.

Ma se hai 1000 possibili ID argomento e 10 possibili ID articolo, Postgres dovrebbe cercare 1000 bucket ID argomento. Molto probabilmente eseguirà invece una scansione completa della tabella. In questo caso vorresti invertire il tuo indice e renderlo (item_id, topic_id) .

Ciò dipende molto dall'avere buone statistiche sulla tabella, il che significa assicurarsi che l'autovacuum funzioni correttamente.

Quindi puoi cavartela con un singolo indice per due colonne, se una colonna ha una variabilità molto inferiore rispetto a un'altra.

Postgres può anche utilizzare più indici se pensa di eseguire la query più veloce . Ad esempio, se avevi un indice su topic_id e un indice su item_id , può utilizzare entrambi gli indici e combinare i risultati. Ad esempio where topic_id = 23 or item_id = 42 potrebbe utilizzare l'indice topic_id per cercare l'ID argomento 23 e l'indice item_id per cercare l'ID elemento 42, quindi combinare i risultati.

Questo è generalmente più lento rispetto ad avere un (topic_id, item_id) composto indice. Può anche essere più lento rispetto all'utilizzo di un singolo indice, quindi non sorprenderti se Postgres decide di non utilizzare più indici.

In generale, per gli indici b-tree, quando hai due colonne hai tre possibili combinazioni.

  • a + b
  • a
  • b

E hai bisogno di due indici.

  • (a, b) -- a e a + b
  • (b) -- b

(a, b) copre entrambe le ricerche per a e a + b. (b) copre la ricerca di b .

Quando hai tre colonne, hai sette possibili combinazioni.

  • a + b + c
  • a + b
  • a + c
  • a
  • b + c
  • b
  • c

Ma ti servono solo tre indici.

  • (a, b, c) -- a, a + b, a + b + c
  • (b, c) -- b, b + c
  • (c, a) -- c, c + a

Tuttavia, probabilmente vorrai effettivamente evitare di avere un indice su tre colonne. Spesso è più lento . Quello che vuoi davvero è questo.

  • (a, b)
  • (b, c)
  • (c, a)

La lettura da un indice è più lenta della lettura dalla tabella. Vuoi che i tuoi indici riducano il numero di righe che devono essere lette, ma non vuoi che Postgres debba eseguire più scansioni dell'indice del necessario.