MongoDB: Ottimizzare le Query con Indici Singoli e Composti

Scopri come gli indici singoli e composti in MongoDB possono trasformare le performance delle tue query, riducendo drasticamente i tempi di risposta e migliorando l'efficienza del tuo database.

Introduzione all'Ottimizzazione con gli Indici in MongoDB

Nel vasto e dinamico mondo della programmazione web, la velocità e l'efficienza sono fattori critici per il successo di qualsiasi applicazione. Quando si lavora con database NoSQL come MongoDB, una delle sfide principali è garantire che le query complesse o su grandi volumi di dati vengano eseguite in tempi accettabili. È qui che entrano in gioco gli indici, strumenti potenti e indispensabili per ottimizzare le performance.

Questa lezione, la ventunesima del nostro corso "Impara MongoDB in 40 lezioni", si immerge nel cuore dell'ottimizzazione delle query, esplorando a fondo il funzionamento e l'applicazione degli indici singoli e composti. Capire come e quando creare gli indici giusti può fare la differenza tra un'applicazione lenta e frustrante e una che offre un'esperienza utente fluida e reattiva. Non si tratta solo di velocizzare le ricerche, ma anche di ridurre il carico sul server e di gestire in modo più efficiente le risorse di sistema. Preparati a scoprire i segreti per rendere le tue applicazioni MongoDB incredibilmente veloci.

Cos'è un Indice MongoDB e Perché è Fondamentale

Un indice in MongoDB è una struttura dati speciale che memorizza una piccola porzione del set di dati in un formato facile da attraversare. L'obiettivo principale di un indice è migliorare l'efficienza delle operazioni di ricerca, ordinamento e join (seppur concettualmente, poiché MongoDB non ha join tradizionali ma piuttosto lookups con $lookup). Senza indici, MongoDB dovrebbe eseguire uno "scan completo della collezione" (COLLSCAN), ovvero scansionare ogni singolo documento nella collezione per selezionare quelli che corrispondono ai criteri della query. Questo processo può essere estremamente lento e dispendioso in termini di risorse, specialmente con collezioni di grandi dimensioni.

Immaginate un libro senza indice. Per trovare tutte le occorrenze di una parola specifica, dovreste sfogliare ogni singola pagina. Con un indice, invece, potete andare direttamente alla pagina o alle pagine pertinenti, risparmiando tempo ed energia. In MongoDB, gli indici funzionano in modo simile, fornendo un accesso rapido ai documenti in base al valore di uno o più campi.

Come Funziona un Indice: La Struttura B-tree

La maggior parte degli indici in MongoDB utilizza una struttura dati chiamata B-tree (albero B). Un B-tree è un albero bilanciato che mantiene i dati ordinati e consente ricerche, inserimenti ed eliminazioni efficienti. Ogni nodo del B-tree può contenere più chiavi e puntatori, e tutti i percorsi dalla radice alle foglie hanno la stessa lunghezza, garantendo che le operazioni abbiano una complessità logaritmica (O(log n)).

Quando si crea un indice su un campo, MongoDB costruisce un B-tree in cui le chiavi sono i valori del campo indicizzato e le foglie contengono i riferimenti ai documenti corrispondenti nella collezione. Quando una query viene eseguita su un campo indicizzato, MongoDB attraversa il B-tree per trovare rapidamente i riferimenti ai documenti desiderati, anziché scansionare l'intera collezione. Questo processo è chiamato "scan dell'indice" (IXSCAN).

Benefici dell'Indicizzazione

  1. Velocità delle Query: Il vantaggio più evidente. Le query che utilizzano indici possono essere ordini di grandezza più veloci dei COLLSCAN.
  2. Ordinamento Efficiente: Le operazioni di ordinamento (sort) su campi indicizzati sono molto più veloci, poiché i dati sono già ordinati nell'indice.
  3. Unicità dei Dati: Gli indici possono far rispettare l'unicità dei valori in un campo, impedendo l'inserimento di documenti duplicati (ad esempio, indirizzi email unici).
  4. Copertura delle Query: Un indice può "coprire" una query se tutti i campi della query (criteri, campi proiettati e campi di ordinamento) sono inclusi nell'indice. In questo caso, MongoDB può soddisfare la query leggendo solo l'indice, senza dover accedere ai documenti della collezione, riducendo ulteriormente il carico I/O.

Costi dell'Indicizzazione

Nonostante i grandi benefici, gli indici non sono privi di costi:

  1. Spazio su Disco: Ogni indice occupa spazio su disco, che può diventare significativo per collezioni molto grandi o con molti indici.
  2. Overhead di Scrittura: Ogni volta che un documento viene inserito, aggiornato o eliminato, anche gli indici su quel documento devono essere aggiornati. Questo aggiunge un overhead alle operazioni di scrittura (insert, update, delete), rallentandole leggermente.
  3. Gestione della Memoria: Gli indici attivi tendono a risiedere nella RAM per prestazioni ottimali. Troppi indici o indici molto grandi possono consumare una quantità significativa di memoria.

È fondamentale trovare un equilibrio tra i benefici in lettura e i costi in scrittura e spazio. Non bisogna indicizzare ogni campo, ma solo quelli che sono frequentemente usati in query, criteri di ordinamento o aggregazioni.

Indici Singoli: La Base delle Performance

Un indice singolo è il tipo più semplice di indice in MongoDB, creato su un singolo campo di una collezione. È la prima linea di difesa contro i COLLSCAN e spesso il punto di partenza per l'ottimizzazione.

Sintassi e Creazione

Per creare un indice singolo, si utilizza il metodo createIndex() sulla collezione. Si specifica un oggetto dove la chiave è il nome del campo e il valore 1 indica l'ordinamento ascendente, mentre -1 indica l'ordinamento discendente.

db.collection.createIndex( { <field>: <1 or -1> } )

Esempio Pratico: Supponiamo di avere una collezione prodotti con documenti che contengono nome, prezzo e categoria. Vogliamo spesso cercare prodotti per categoria.

// Inseriamo alcuni dati di esempio
db.prodotti.insertMany([
  { nome: "Laptop", prezzo: 1200, categoria: "Elettronica", disponibilita: 50 },
  { nome: "Smartphone", prezzo: 800, categoria: "Elettronica", disponibilita: 120 },
  { nome: "Tastiera Meccanica", prezzo: 150, categoria: "Accessori", disponibilita: 200 },
  { nome: "Mouse Wireless", prezzo: 50, categoria: "Accessori", disponibilita: 300 },
  { nome: "Libro di Fantascienza", prezzo: 25, categoria: "Libri", disponibilita: 100 },
  { nome: "Cuffie Bluetooth", prezzo: 100, categoria: "Elettronica", disponibilita: 80 }
]);

// Creiamo un indice sul campo 'categoria' in ordine ascendente
db.prodotti.createIndex( { categoria: 1 } );

// Output atteso (simile):
// { "createdCollectionAutomatically" : false, "numIndexesBefore" : 1, "numIndexesAfter" : 2, "ok" : 1 }

Dopo aver creato l'indice, le query che filtrano per categoria saranno molto più veloci. Ad esempio:

db.prodotti.find( { categoria: "Elettronica" } ).explain("executionStats")

Analizzando l'output di explain(), vedremo che MongoDB utilizza un IXSCAN (Index Scan) invece di un COLLSCAN per soddisfare la query, indicando che l'indice è stato utilizzato con successo.

Ordine dell'Indice (Ascendente/Discendente)

Per gli indici singoli, l'ordine (1 per ascendente, -1 per discendente) di solito non ha un impatto significativo sulla velocità delle query di uguaglianza ({ campo: "valore" }). MongoDB può attraversare un B-tree in entrambe le direzioni con la stessa efficienza. Tuttavia, l'ordine diventa rilevante in due scenari principali:

  1. Query di Range: Se si eseguono query che specificano un intervallo ($gt, $lt, $gte, $lte) e si desidera che i risultati vengano restituiti in un certo ordine. Ad esempio, un indice { prezzo: 1 } è più efficiente per trovare prodotti con prezzo > X e ordinarli per prezzo ascendente.
  2. Query di Ordinamento: Se si ordina (sort) il risultato di una query. Un indice con lo stesso ordine del criterio di ordinamento può evitare un'operazione di ordinamento in memoria (in-memory sort), che può essere costosa per grandi set di risultati. Se la query ordina per campo: 1 e l'indice è { campo: 1 } (o campo: -1 se la query ordina per campo: -1), l'indice può soddisfare direttamente l'ordinamento.
// Indice per ottimizzare query di prezzo e ordinamento
db.prodotti.createIndex( { prezzo: 1 } );

// Query che beneficia dell'indice per filtro e ordinamento
db.prodotti.find( { prezzo: { $gt: 100 } } ).sort( { prezzo: 1 } ).explain("executionStats");

In questo caso, l'indice { prezzo: 1 } è perfettamente allineato sia con il filtro di range che con l'ordinamento, portando a prestazioni ottimali.

Indici Composti: Ottimizzare Query Complesse

Gli indici composti sono indici che includono più campi in un ordine specifico. Sono essenziali quando le query coinvolgono più criteri di filtro e/o ordinamento, permettendo a MongoDB di ottimizzare l'accesso ai dati in base alla combinazione di questi campi.

Cosa Sono e Quando Sono Necessari

Un indice composto è una lista ordinata di campi. L'ordine dei campi nell'indice è cruciale perché determina l'efficacia dell'indice per diverse query. MongoDB ordina i documenti prima per il primo campo dell'indice, poi per il secondo, e così via.

Sono necessari quando:

  • Le tue query filtrano su più campi contemporaneamente.
  • Le tue query filtrano su alcuni campi e ordinano su altri.
  • Hai bisogno di garantire l'unicità su una combinazione di campi.

Sintassi e Creazione

La sintassi è simile a quella degli indici singoli, ma si specificano più campi nell'oggetto, mantenendo l'ordine desiderato.

db.collection.createIndex( { <field1>: <1 or -1>, <field2>: <1 or -1>, ... } )

Esempio Pratico: Continuando con la collezione prodotti, supponiamo di voler spesso cercare prodotti per categoria e poi, all'interno di quella categoria, ordinarli per prezzo.

// Creiamo un indice composto su 'categoria' (ascendente) e 'prezzo' (ascendente)
db.prodotti.createIndex( { categoria: 1, prezzo: 1 } );

// Query che beneficia di questo indice composto
db.prodotti.find( { categoria: "Elettronica", prezzo: { $lte: 1000 } } ).sort( { prezzo: 1 } ).explain("executionStats");

Questo indice è estremamente efficace per query che filtrano per categoria e poi per prezzo, o che filtrano per categoria e ordinano per prezzo. MongoDB può usare l'indice per trovare i documenti nella categoria specificata e poi scansionare solo quella parte dell'indice, che è già ordinata per prezzo.

La Regola della "Prefisso" (Prefix Rule)

Una delle proprietà più importanti degli indici composti è la "regola della prefisso". Un indice composto (A, B, C) può supportare query che usano:

  • Solo A (prefisso).
  • A e B (prefisso).
  • A, B e C.

Non può supportare query che usano solo B, o B e C, o solo C, a meno che non ci siano altri indici pertinenti. Questo perché l'indice è ordinato gerarchicamente: prima per A, poi per B all'interno di A, e così via.

Esempio con (categoria: 1, prezzo: 1, disponibilita: -1):

  • db.prodotti.find( { categoria: "Elettronica" } ) - USA L'INDICE (copre categoria)
  • db.prodotti.find( { categoria: "Elettronica", prezzo: { $gt: 100 } } ) - USA L'INDICE (copre categoria e prezzo)
  • db.prodotti.find( { categoria: "Elettronica" } ).sort( { prezzo: 1 } ) - USA L'INDICE (copre categoria e prezzo per ordinamento)
  • db.prodotti.find( { prezzo: { $gt: 100 } } ) - NON USA QUESTO INDICE (il prefisso categoria manca), potrebbe usare un indice singolo su prezzo se esistente, altrimenti COLLSCAN.
  • db.prodotti.find( { categoria: "Elettronica" } ).sort( { disponibilita: -1 } ) - NON USA QUESTO INDICE per l'ordinamento (il campo disponibilita non è il successivo nel prefisso dopo categoria), potrebbe fare IXSCAN per il filtro e poi un in-memory sort.

Ordine dei Campi negli Indici Composti

La scelta dell'ordine dei campi in un indice composto è fondamentale per massimizzarne l'efficacia. Una buona euristica è seguire l'Equality, Sort, Range (ESR) rule:

  1. Equality (E): Mettere per primi i campi su cui si eseguono query di uguaglianza ({ campo: "valore" }). Questi campi riducono drasticamente il numero di documenti da considerare.
  2. Sort (S): Mettere poi i campi su cui si ordina (sort). Se l'ordinamento corrisponde all'ordine dell'indice, MongoDB può evitare un'operazione di ordinamento costosa.
  3. Range (R): Mettere per ultimi i campi su cui si eseguono query di intervallo ($gt, $lt, $gte, $lte). Se un campo di range è posizionato prima di un campo di uguaglianza o ordinamento, l'indice potrebbe non essere in grado di soddisfare le parti successive della query in modo efficiente a causa della natura del B-tree (una volta che si entra in un range, l'ordinamento preciso dei campi successivi potrebbe non essere mantenuto per tutti i valori del range).

Esempio: Query: db.prodotti.find( { categoria: "Elettronica", disponibilita: { $gt: 10 } } ).sort( { prezzo: 1 } )

Secondo la regola ESR:

  • Equality: categoria
  • Sort: prezzo
  • Range: disponibilita

Quindi, l'indice ottimale sarebbe: { categoria: 1, prezzo: 1, disponibilita: 1 } (o -1 a seconda dell'ordinamento desiderato per disponibilita).

Analizzare e Ottimizzare con explain()

Il metodo explain() è il vostro migliore amico quando si tratta di capire come MongoDB esegue le query e se sta utilizzando gli indici in modo efficace. Permette di visualizzare il "piano di esecuzione" di una query, fornendo dettagli preziosi sulle operazioni eseguite.

Uso di explain()

Si può chiamare explain() su qualsiasi operazione di lettura (find, aggregate, count, distinct) e specificare un "verbosity mode":

  • "queryPlanner": Mostra il piano di query scelto dal query optimizer, ma non esegue la query. Utile per capire quali indici verrebbero usati.
  • "executionStats": Esegue la query e mostra il piano di query, le statistiche di esecuzione (tempo, documenti scansionati, documenti restituiti) e i dettagli sull'uso dell'indice. Questo è il più utile per l'ottimizzazione.
  • "allPlansExecution": Esegue la query e mostra il piano di query, le statistiche di esecuzione e i dettagli su tutti i piani di query esaminati dal query optimizer.
db.prodotti.find( { categoria: "Elettronica" } ).sort( { prezzo: -1 } ).explain("executionStats")

Interpretare l'Output di explain()

Quando analizzate l'output di explain("executionStats"), cercate queste informazioni chiave:

  • "winningPlan": Dettagli sul piano di esecuzione scelto.
  • "stage": Indica il tipo di operazione. I valori più importanti sono:
    • "COLLSCAN": Scansione completa della collezione. Segnale di allarme! Indica che nessun indice è stato usato o che l'indice disponibile non era sufficientemente selettivo. Da evitare per query frequenti su grandi collezioni.
    • "IXSCAN": Scansione dell'indice. Ottimo! Indica che un indice è stato usato per trovare i documenti.
    • "FETCH": Recupero dei documenti dalla collezione dopo che l'indice ha fornito i riferimenti.
    • "SORT": Operazione di ordinamento. Se non è seguita da IXSCAN o se sort in memory è true, indica un ordinamento costoso che potrebbe essere ottimizzato con un indice.
  • "indexName": Il nome dell'indice utilizzato (se applicabile).
  • "totalDocsExamined": Il numero totale di documenti esaminati durante l'esecuzione della query. L'obiettivo è che questo numero sia il più vicino possibile a totalDocsReturned (o nReturned). Un alto rapporto totalDocsExamined / totalDocsReturned indica che la query sta esaminando molti documenti inutili.
  • "totalKeysExamined": Il numero totale di chiavi dell'indice esaminate. Simile a totalDocsExamined ma per l'indice.
  • "nReturned": Il numero di documenti restituiti dalla query.
  • "executionTimeMillis": Il tempo totale impiegato per eseguire la query. L'obiettivo è minimizzare questo valore.

Esempio di analisi:

Se vedete un COLLSCAN e totalDocsExamined è uguale al numero totale di documenti nella collezione, significa che la query non sta usando un indice. Se vedete un IXSCAN e totalKeysExamined è basso rispetto al numero totale di chiavi nell'indice, e totalDocsExamined è vicino a nReturned, allora la query è ben ottimizzata.

Strategie Avanzate per l'Indicizzazione

Oltre agli indici singoli e composti, MongoDB offre diverse opzioni avanzate per affinare ulteriormente le strategie di indicizzazione.

Indici Unici (unique: true)

Gli indici unici garantiscono che non ci siano due documenti nella collezione con lo stesso valore per il campo indicizzato. Se si tenta di inserire un documento con un valore duplicato, MongoDB genererà un errore. Sono fondamentali per campi come email o username.

db.utenti.createIndex( { email: 1 }, { unique: true } );

Indici Parziali (partialFilterExpression)

Gli indici parziali indicizzano solo i documenti di una collezione che soddisfano una condizione specificata. Questo può ridurre le dimensioni dell'indice e l'overhead di scrittura, rendendoli più efficienti per i casi d'uso in cui solo un sottoinsieme dei documenti deve essere indicizzato.

Esempio: indicizzare solo i prodotti che sono attivi e hanno una quantita maggiore di 0.

db.prodotti.createIndex(
  { nome: 1 },
  { partialFilterExpression: { attivo: true, quantita: { $gt: 0 } } }
);

Indici TTL (expireAfterSeconds)

Gli indici TTL (Time-To-Live) sono indici speciali che consentono a MongoDB di eliminare automaticamente i documenti da una collezione dopo un certo periodo di tempo. Sono ideali per dati come log, sessioni o cache che non devono essere conservati indefinitamente.

Esempio: eliminare i documenti della collezione log dopo 24 ore (86400 secondi) dalla loro creazione.

db.log.createIndex( { createdAt: 1 }, { expireAfterSeconds: 86400 } );

Indici Sparse (sparse: true)

Gli indici sparse indicizzano solo i documenti che contengono il campo indicizzato. Se un documento non ha il campo, non verrà incluso nell'indice. Questo è utile per risparmiare spazio e migliorare le prestazioni quando un campo è presente solo in una piccola percentuale di documenti.

Esempio: indicizzare un campo dataFinePromozione che è presente solo per i prodotti in promozione.

db.prodotti.createIndex( { dataFinePromozione: 1 }, { sparse: true } );

Esempi Pratici e Casi d'Uso Reali

Vediamo alcuni scenari comuni e come gli indici possono risolverli.

Scenario 1: Ricerca di Utenti per Nome e Status

Consideriamo una collezione utenti con campi nome, cognome, email, status (attivo, inattivo, sospeso). Le query tipiche potrebbero essere:

  • Trova tutti gli utenti attivi il cui nome inizia con 'J'.
  • Trova tutti gli utenti inattivi e ordinali per cognome.

Query: db.utenti.find( { status: "attivo", nome: /^J/ } ).sort( { cognome: 1 } )

Indice ottimale (ESR):

  1. Equality: status
  2. Sort: cognome
  3. Range: nome (la regex ^J agisce come un range scan su un prefisso)

Quindi, l'indice suggerito è: { status: 1, cognome: 1, nome: 1 }.

db.utenti.createIndex( { status: 1, cognome: 1, nome: 1 } );

Questo indice permetterebbe a MongoDB di filtrare rapidamente per status, poi, all'interno degli utenti attivi, di scansionare i cognome già ordinati e infine applicare il filtro nome all'interno di questi sottogruppi. Se la query non includesse l'ordinamento, un indice { status: 1, nome: 1 } sarebbe già sufficiente per le prime due parti.

Scenario 2: Analisi di Log con Data e Livello di Gravità

Una collezione log memorizza eventi con campi timestamp, livello (INFO, WARN, ERROR), messaggio.

Query: db.log.find( { timestamp: { $gte: ISODate("2023-01-01T00:00:00Z") }, livello: "ERROR" } ).sort( { timestamp: -1 } )

Indice ottimale (ESR):

  1. Equality: livello
  2. Sort: timestamp (ma qui l'ordinamento è discendente, quindi l'indice dovrebbe essere timestamp: -1)
  3. Range: timestamp (il range è coperto dal campo di ordinamento)

Quindi, l'indice suggerito è: { livello: 1, timestamp: -1 }.

db.log.createIndex( { livello: 1, timestamp: -1 } );

Questo indice permette di trovare rapidamente tutti gli errori e poi di scansionare quei documenti in ordine cronologico inverso, soddisfacendo sia il filtro che l'ordinamento senza un'operazione di sort in memoria.

Scenario 3: Indici Geospaziali (Breve Menzione)

MongoDB supporta anche indici geospaziali (2d, 2dsphere) per query su dati geografici. Sebbene non approfonditi in questa lezione, sono un esempio eccellente di indici specializzati per tipi di query molto specifici. Ad esempio, per trovare tutti i punti entro un certo raggio da una coordinata.

db.luoghi.createIndex( { posizione: "2dsphere" } );

Errori Comuni e Best Practices

L'indicizzazione è potente, ma un uso improprio può portare a problemi di performance anziché risolverli.

Errori Comuni

  1. Troppi Indici: Ogni indice ha un costo. Troppi indici rallentano le scritture, occupano spazio su disco e consumano RAM. Indicizzare solo i campi che sono frequentemente usati nelle query.
  2. Indici Non Usati: Creare indici che non vengono mai utilizzati dalle query è uno spreco di risorse. Usate explain() regolarmente per verificare l'efficacia dei vostri indici.
  3. Ordine Sbagliato nei Compounded Indexes: Come visto con la regola ESR, l'ordine dei campi è critico. Un ordine subottimale può rendere l'indice inutile per alcune query.
  4. Indicizzare Campi con Bassa Cardinalità: Indicizzare un campo con pochi valori unici (es. genere: ['M', 'F']) spesso non porta grandi benefici, poiché il filtro su tale campo non riduce significativamente il numero di documenti da scansionare. MongoDB potrebbe preferire un COLLSCAN se l'indice non è sufficientemente selettivo.
  5. Ignorare i Costi di Scrittura: In applicazioni con un alto carico di scrittura, l'overhead degli indici può essere un problema. Valutate sempre il tradeoff tra letture e scritture.

Best Practices

  1. Monitora le Performance: Usa strumenti come MongoDB Atlas Performance Advisor o db.currentOp() e i log del database per identificare query lente e quali indici mancano o sono sottoutilizzati.
  2. Usa explain() Regolarmente: È il tuo strumento diagnostico principale. Prima di creare un nuovo indice, testa la query con explain() per capire il suo piano attuale. Dopo aver creato l'indice, testa di nuovo per confermare che venga utilizzato.
  3. Applica la Regola ESR: Per gli indici composti, segui l'ordine Equality, Sort, Range per massimizzare la loro efficacia.
  4. Crea Indici in Background: Per evitare di bloccare le operazioni di scrittura su collezioni di grandi dimensioni, crea gli indici con l'opzione background: true (anche se nelle versioni più recenti di MongoDB, createIndex è bloccante solo per il database, non per il singolo shard/replica set, e la maggior parte delle operazioni di creazione indice sono ora non bloccanti per default per i replica set e shard cluster).
    // Nelle versioni moderne, spesso non necessario, ma utile sapere
    db.prodotti.createIndex( { campo: 1 }, { background: true } );
    
  5. Pulisci gli Indici Inutilizzati: Controlla regolarmente quali indici non vengono mai usati e rimuovili per ridurre l'overhead.
    • Per vedere l'uso degli indici: db.collection.aggregate([ { $indexStats: {} } ])
  6. Testa su Dati Reali (o Simil-reali): Le performance degli indici dipendono dalla distribuzione e dal volume dei dati. Testa le tue strategie di indicizzazione su un ambiente che riflette il più possibile la produzione.

Gestione degli Indici: Rimuovere e Ricostruire

Oltre alla creazione, è importante sapere come gestire gli indici esistenti.

Elencare gli Indici

Per vedere tutti gli indici di una collezione:

db.prodotti.getIndexes()

Rimuovere un Indice

Si può rimuovere un indice per nome o per specifica. MongoDB assegna un nome predefinito agli indici (es. campo_1 per { campo: 1 }), ma è buona pratica assegnare nomi significativi ({ name: "idx_categoria_prezzo" }) al momento della creazione per facilitarne la gestione.

// Rimuovere per nome
db.prodotti.dropIndex("categoria_1_prezzo_1"); // Nome generato automaticamente
db.prodotti.dropIndex("idx_prodotti_categoria_prezzo"); // Nome personalizzato

// Rimuovere specificando l'indice (utile se non si conosce il nome)
db.prodotti.dropIndex( { categoria: 1, prezzo: 1 } );

Per rimuovere tutti gli indici di una collezione (tranne l'_id index):

db.prodotti.dropIndexes();

Ricostruire Indici

In alcuni casi, potrebbe essere necessario ricostruire un indice, ad esempio dopo un aggiornamento significativo del database o per cambiare alcune delle sue proprietà (che richiedono la ricreazione). Nelle versioni recenti di MongoDB, db.collection.createIndex() è intelligente e, se l'indice esiste già con la stessa specifica, non fa nulla. Se si tenta di creare un indice con lo stesso nome ma specifiche diverse, darà un errore. Per "ricostruire" un indice, di solito si intende eliminarlo e poi ricrearlo.

Prossimi Passi

Con la comprensione degli indici singoli e composti, avete ora uno strumento potentissimo per migliorare le prestazioni delle vostre applicazioni MongoDB. Tuttavia, il viaggio nell'ottimizzazione non finisce qui:

  • Indici Text: Approfondisci gli indici di testo per ricerche full-text sui contenuti dei documenti.
  • Indici Hashed: Esplora gli indici hashed per lo sharding basato su hash.
  • Aggregation Framework: Impara come gli indici influenzano le pipeline di aggregazione e come ottimizzare le operazioni complesse con $lookup, $match, $sort e $group.
  • Sharding: Scopri come l'indicizzazione è fondamentale per una strategia di sharding efficace, soprattutto con le shard keys.
  • Monitoraggio Avanzato: Utilizza strumenti di monitoraggio professionali per tenere d'occhio le performance del tuo database in produzione e identificare proattivamente i colli di bottiglia.

Ricorda, l'indicizzazione è un'arte e una scienza. Richiede sperimentazione, analisi e un'attenta considerazione dei pattern di accesso ai dati della tua applicazione. Ma con la pratica e gli strumenti giusti, potrai sbloccare il vero potenziale di performance di MongoDB.