---
term: 'Indice del database'
seoTitle: 'Indice del database: come funziona l''indicizzazione'
headline: 'Che cos''è un indice del database?'
slug: indice-del-database
category: database
shortDefinition: 'Un indice del database è una struttura di ricerca ordinata che permette al motore di trovare le righe corrispondenti senza scansionare l''intera tabella.'
relatedTerms:
  - database-queries
  - n-plus-one-query-problem
  - database-schema
  - multi-tenant-database-architecture
contrastsWith:
  - database-queries
faq:
  - question: 'Che cos''è un indice del database, in parole semplici?'
    answer: 'Una struttura separata e ordinata – di solito un B-tree – che contiene i valori di una colonna più i puntatori alle loro righe, esattamente come l''indice analitico di un libro contiene i termini più i numeri di pagina. Il motore cerca il valore nella piccola struttura ordinata e salta direttamente alle righe corrispondenti, invece di leggere l''intera tabella sperando di trovarle.'
  - question: 'Quanto è più veloce una query indicizzata?'
    answer: 'È la differenza tra lavoro logaritmico e lavoro lineare: una ricerca in un B-tree tocca una manciata di pagine, sia che la tabella contenga diecimila righe sia che ne contenga cento milioni, mentre una scansione completa legge tutto. Alle piccole dimensioni entrambe sembrano istantanee – ed è per questo che gli indici mancanti si nascondono in sviluppo e detonano in produzione, dove la stessa query esamina all''improvviso milioni di righe.'
  - question: 'Gli indici rallentano le scritture?'
    answer: 'Sì – è questa la tassa. Ogni inserimento, aggiornamento o cancellazione su una colonna indicizzata deve aggiornare anche ogni indice che la riferisce: sei indici su una tabella significano fino a sei aggiornamenti di struttura in più per scrittura, oltre all''archiviazione che occupano. Gli indici sono un acquisto di velocità in lettura pagato in velocità di scrittura e in disco – quelli deliberati se lo guadagnano, quelli dimenticati si limitano a presentare il conto.'
  - question: 'Quali colonne conviene indicizzare?'
    answer: 'Le colonne che le query usano davvero: i filtri (WHERE), le chiavi di join – comprese le chiavi esterne e i campi puntatore, che alcuni motori non indicizzano automaticamente – e le colonne di ordinamento (ORDER BY). A questo va aggiunto il test della selettività: una colonna email che distingue milioni di righe si merita il proprio indice; un flag booleano che taglia la tabella in due, di norma, no.'
  - question: 'In che ordine vanno le colonne di un indice composito?'
    answer: 'Prima l''uguaglianza, poi intervalli e ordinamento – e va ricordata la regola del prefisso sinistro: un indice su (a, b, c) serve le query che filtrano su a, su a e b, o su tutte e tre, ma non su b da solo. La formulazione della stessa regola nei database documentali è ESR: Equality, Sort, Range. L''ordine delle colonne è la differenza tra un indice composito che funziona e un indice che si limita a esistere.'
  - question: 'Come si trovano gli indici mancanti o inutilizzati?'
    answer: 'Per quelli mancanti: si esegue il piano di esecuzione – EXPLAIN – e si cercano le scansioni complete sulle tabelle grandi; la colonna di filtro di una query lenta e frequente è la candidata. Per quelli inutilizzati: ogni motore tiene statistiche di utilizzo degli indici, e un indice che nessuna query ha toccato da mesi è pura tassa sulle scritture, da eliminare. Il piano e le statistiche, insieme, sono tutta la metodologia.'
  - question: 'Che cosa sono gli indici univoci, parziali e di copertura?'
    answer: 'Specializzazioni della stessa struttura: un indice univoco impone l''assenza di duplicati come vincolo e intanto accelera le ricerche; un indice parziale copre solo le righe che soddisfano una condizione – piccolo e rapido per i sottoinsiemi caldi come gli ordini non spediti; un indice di copertura contiene tutte le colonne di cui una query ha bisogno, così il motore risponde dal solo indice senza visitare la tabella.'
  - question: 'L''indicizzazione funziona allo stesso modo nei database documentali?'
    answer: 'Concettualmente identica – B-tree sui valori dei campi – con gli stessi trade-off e la stessa logica del prefisso sinistro sotto la regola empirica ESR. I database documentali aggiungono gli indici multikey sui campi array e le varianti geospaziali, e la regola operativa sopravvive alla traduzione: indicizzare ciò che si interroga, soprattutto i campi puntatore che join e include attraversano.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'PostgreSQL index types documentation'
    url: 'https://www.postgresql.org/docs/current/indexes-types.html'
  - name: 'Database index (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Database_index'
  - name: 'MongoDB indexes documentation'
    url: 'https://www.mongodb.com/resources/basics/databases/database-index'
  - name: 'PostgreSQL — Using EXPLAIN'
    url: 'https://www.postgresql.org/docs/current/using-explain.html'
cta:
  title: 'Query veloci, indici visibili'
  text: 'Back4app mette la gestione degli indici dove vive lo schema: indici da creare e rivedere per classe nella dashboard, sullo stesso archivio basato su MongoDB che le query interrogano davvero – senza script di migrazione e senza indovinare di quali campi hanno bisogno i filtri.'
  linkText: 'Inizia gratis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-10-05'
translationKey: database-index
---

**Un indice del database è una struttura di ricerca ordinata che permette al motore di trovare le righe corrispondenti senza scansionare l'intera tabella.** L'analogia del libro è esatta: nessuno trova "idempotenza" in un volume di 900 pagine leggendolo – si consulta l'indice e si salta alla pagina. I database fanno la stessa scelta a ogni query, e il fatto che *possano* saltare o no è la differenza più comune tra una query da 5 millisecondi e una da 5 secondi.

## Punti chiave

| Domanda | Risposta |
| --- | --- |
| Che cos'è | Una struttura ordinata a lato: valori + puntatori, come l'indice di un libro |
| Il guadagno | Ricerca logaritmica invece di scansione lineare – decisiva su larga scala |
| La tassa | Ogni scrittura aggiorna ogni indice; l'archiviazione cresce |
| Che cosa indicizzare | Colonne di filtro, di join/puntatore e di ordinamento – se selettive |
| La diagnosi | EXPLAIN: una scansione completa su una tabella grande è la spia |

## L'indice, creato e percepito

```sql
-- Il cavallo da tiro: un indice composito sagomato sulla query calda
CREATE INDEX orders_pending ON orders (status, created_at);

-- Specializzazioni della stessa idea:
CREATE UNIQUE INDEX users_email ON users (email);         -- vincolo + velocità
CREATE INDEX unshipped ON orders (created_at)
  WHERE shipped = false;                                  -- parziale: solo il sottoinsieme caldo

-- Il prima/dopo, visto dal piano:
EXPLAIN SELECT * FROM orders WHERE status = 'pending' AND created_at > now() - interval '1 day';
--  prima:   Seq Scan on orders   (righe esaminate: 4.812.309)
--  dopo:    Index Scan using orders_pending   (righe esaminate: 1.214)
```

Il codice applicativo incontra la stessa fisica attraverso la forma della query – questa query *è* la specifica dell'indice `(status, createdAt)`, qualunque sia la superficie che la scrive:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// The query shape tells you the index: (status, createdAt)
const query = new Parse.Query('Order');
query.equalTo('status', 'pending');       // equality first…
query.greaterThan('createdAt', since);    // …then the range
query.descending('createdAt');            // …sorted by the same column
const backlog = await query.find();
// Indexed: milliseconds at any size. Unindexed: a full collection scan.
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// The query shape tells you the index: (status, createdAt)
final query = QueryBuilder<ParseObject>(ParseObject('Order'))
  ..whereEqualTo('status', 'pending')      // equality first…
  ..whereGreaterThan('createdAt', since)   // …then the range
  ..orderByDescending('createdAt');        // …sorted by the same column
final response = await query.query();
// Indexed: milliseconds at any size. Unindexed: a full collection scan.
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// The query shape tells you the index: (status, createdAt)
let query = Order.query("status" == "pending", "createdAt" > since)
  .order([.descending("createdAt")])
query.find { result in
  if case .success(let backlog) = result { render(backlog) }
}
// Indexed: milliseconds at any size. Unindexed: a full collection scan.
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// The query shape tells you the index: (status, createdAt)
val query = ParseQuery.getQuery<ParseObject>("Order")
query.whereEqualTo("status", "pending")     // equality first…
query.whereGreaterThan("createdAt", since)  // …then the range
query.orderByDescending("createdAt")        // …sorted by the same column
query.findInBackground { backlog, e -> if (e == null) render(backlog) }
// Indexed: milliseconds at any size. Unindexed: a full collection scan.
```

## Come funziona il salto

```mermaid
flowchart TB
  accTitle: Una ricerca in un indice B-tree
  accDescr: Una query scende un albero ordinato e poco profondo dalla radice, passando per un nodo intermedio, fino a una foglia che contiene il valore cercato e i puntatori alle righe, toccando una manciata di pagine invece di scansionare l'intera tabella.
  R["Nodo radice<br/>(intervalli)"] --> B1["Ramo<br/>A–M"]
  R --> B2["Ramo<br/>N–Z"]
  B2 --> L1["Foglia: 'pending' → righe 88, 1042, 55913"]
  B1 --> L2["Foglia …"]
  L1 --> T["Recupera esattamente quelle righe"]
```

La struttura predefinita, in ogni motore, è il **B-tree**: poco profondo, ordinato, auto-bilanciato – tre o quattro livelli coprono centinaia di milioni di voci, e le sue foglie sono concatenate, ed è per questo che una sola struttura serve allo stesso modo uguaglianza, intervalli e `ORDER BY`. È questa versatilità a rendere "nel dubbio, B-tree" il consiglio permanente, con le alternative nel ruolo di specialiste.

## B-tree vs. hash vs. gli specialisti

### Quale tipo di indice conviene usare?

| Tipo | Supporta | Sceglierlo quando |
| --- | --- | --- |
| B-tree (predefinito) | `=`, `<`, `>`, intervalli, ordinamenti, prefissi | Quasi sempre – il generalista |
| Hash | Solo uguaglianza, O(1) | Ricerche per corrispondenza esatta, nient'altro |
| Composito | Multi-colonna, prefisso sinistro | La query calda filtra su più colonne |
| Univoco | B-tree + nessun duplicato | Vincolo e indice in uno |
| Parziale | Una fetta filtrata di righe | Sottoinsiemi caldi: non spedito, non letto, attivo |
| Di copertura | Query risolta dal solo indice | Query a prevalenza di lettura con un elenco di colonne stabile |
| Full-text (invertito) | Parole → documenti | Caselle di ricerca |
| Geospaziale | Punti, regioni, distanza | Query "vicino a me" |

Due regole reggono la riga del composito: la regola del **prefisso sinistro** – un indice su `(a, b, c)` serve `a`, `(a, b)`, `(a, b, c)`, mai `b` da solo – e **prima l'uguaglianza, intervallo e ordinamento per ultimi** nell'ordine delle colonne (il mnemonico ESR dell'[indicizzazione nei database documentali](https://www.mongodb.com/resources/basics/databases/database-index), dove gli stessi B-tree fanno lo stesso lavoro).

## Quando indicizzare – e quando no

**Indicizzare:** le colonne nei filtri `WHERE` frequenti; le chiavi di join e i campi puntatore (alcuni motori non indicizzano mai le chiavi esterne in automatico – un classico della scansione silenziosa); le colonne `ORDER BY` sui percorsi caldi; e sempre con la selettività in mente – una colonna email (milioni di valori distinti) si guadagna il posto, un flag di stato (tre valori) di norma no da solo, anche se brilla *in testa a un composito* con un intervallo dietro. **Non indicizzare:** le tabelle piccole che il motore scansiona più in fretta di quanto cerchi; le tabelle calde in scrittura oltre i pochi indici essenziali; le colonne già servite dal prefisso sinistro di un indice esistente; e tutto ciò per cui non si sa nominare una query – un indice senza query è pura tassa sulle scritture. Il ciclo di verifica: passare [EXPLAIN](https://www.postgresql.org/docs/current/using-explain.html) sulle query lente in cerca di scansioni, controllare le statistiche di utilizzo per trovare gli indici morti, aggiungere ed eliminare di conseguenza.

## Casi d'uso tipici

- **La query della lista calda.** Filtri su stato più data dietro ogni dashboard e ogni feed – il terreno di casa dell'indice composito.
- **Campi di accesso e di ricerca.** Email, username, ID esterni – indici univoci che fanno vincolo e velocità in una mossa.
- **Percorsi di join e di puntatore.** Ogni chiave esterna e ogni puntatore che le query attraversano; il complice silenzioso del problema N+1 è uno di questi non indicizzato.
- **Filtri multi-tenant.** Compositi che iniziano dal tenant – la [regola dell'architettura multi-tenant](/glossary/it/architettura-database-multi-tenant/) per cui ogni indice parte da `tenant_id`.
- **Ricerca e geo.** Indici invertiti e spaziali che alimentano le query fuori portata dei B-tree.

## Conviene aggiungere quell'indice? Matrice decisionale

| Aggiungerlo quando… | Lasciar perdere quando… |
| --- | --- |
| Una query frequente filtra o ordina su quella colonna | Nessuna query in produzione la usa |
| EXPLAIN mostra scansioni su una tabella che cresce | La tabella è piccola e resta piccola |
| La colonna è selettiva (molti valori distinti) | Il prefisso di un indice esistente la copre già |
| È una chiave di join o un campo puntatore | La tabella è dominata dalle scritture e la lettura è rara |
| Serve comunque imporre una regola di univocità | Si sta tirando a indovinare: prima misurare |

La disciplina in una frase: gli indici si creano in risposta alle query, si rivedono rispetto all'uso effettivo e si eliminano senza sentimentalismi.

## Limiti e trade-off

- **Le scritture pagano le letture.** Ogni indice è un'altra struttura che ogni scrittura deve mantenere – i caricamenti in massa, com'è noto, vanno più veloci con gli indici eliminati prima e ricostruiti dopo.
- **L'archiviazione è reale.** Gli indici rivaleggiano spesso con la dimensione della tabella stessa; quelli di copertura in particolare barattano disco per velocità.
- **Decide l'ottimizzatore, non chi scrive la query.** Un indice poco selettivo può essere ignorato a ragione; statistiche stantie possono far ignorare a torto un indice buono – il piano è la verità.
- **Gli errori di ordine neutralizzano i compositi.** `(created_at, status)` e `(status, created_at)` sono strumenti diversi; la regola del prefisso sinistro non perdona nulla.
- **Gli indici non aggiustano la query.** Wildcard iniziali, funzioni applicate alle colonne e cicli N+1 sconfiggono l'indicizzazione dall'alto – la forma della query viene prima.

## Indici su Back4app

Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. La gestione degli indici vive accanto allo schema nella dashboard: si creano, si rivedono e si eliminano indici per classe – a campo singolo o composti – sull'archivio basato su MongoDB che le query dell'SDK interrogano davvero, seguendo la stessa logica dei B-tree e dell'ESR vista sopra. La query nelle schede di codice e l'indice che la serve si progettano nello stesso posto, che è esattamente dove vuole stare la disciplina di indicizzare ciò che si interroga.
