Senza indice il database legge ogni riga per rispondere a una domanda. Con quello giusto salta dritto alla risposta. Su una tabella grande la differenza è fra secondi e microsecondi — e l'indice sbagliato è peggio di nessun indice, perché costa in scrittura e non dà nulla.

Indicizza ciò su cui FILTRI

La clausola WHERE, poi ORDER BY, poi le colonne di unione. Non ciò che metti nel SELECT: non è quello che usa la ricerca.

SELECT * FROM orders WHERE customer_id = 42 ORDER BY created_at DESC;
CREATE INDEX idx_orders_customer_created ON orders (customer_id, created_at);

In un indice composto l'ordine conta

Un indice composto si usa da sinistra a destra, come un elenco telefonico ordinato per cognome e poi per nome. Ordinato così puoi trovare tutti quelli di cognome Ali; non puoi trovare tutti quelli che di nome fanno Mohamed.

  • (customer_id, created_at) serve un filtro su customer_id, e uno su entrambe.
  • NON serve un filtro sulla sola created_at.
  • Metti per prima la colonna su cui filtri per uguaglianza, e per seconda l'intervallo o l'ordinamento.

Dimostra che venga davvero usato

EXPLAIN SELECT * FROM orders WHERE customer_id = 42;

type: ref oppure const significa che l'indice è in uso. type: ALL significa scansione completa, cioè indice ignorato — di solito perché la colonna è avvolta in una funzione.

WHERE DATE(created_at) = "2026-01-01" non può usare un indice su created_at: la funzione deve prima girare su ogni riga. Scrivilo invece come intervallo: created_at >= "2026-01-01" AND created_at < "2026-01-02".

Perché non indicizzare tutto

  • Ogni indice viene aggiornato a ogni INSERT, UPDATE e DELETE. Dieci indici rendono le scritture parecchie volte più lente.
  • Occupano disco, a volte più della tabella stessa.
  • Il pianificatore ha più scelte e ogni tanto ne prende una peggiore.
Aggiungi l'indice che il registro delle lentezze ha nominato, misura e fermati. Aggiungere indici per ipotesi è il modo in cui un database rallenta pur sembrando messo a punto.