Best practice da seguire con gli indici del database [chiuso]


17

Quali sono alcuni DO e DONT per migliorare le prestazioni del database usando l'indice?

Un DO sarebbe un caso in cui dovrebbe essere creato un indice o un altro suggerimento relativo agli indici che migliorerà le prestazioni.

Un DONT sarà un caso in cui un indice non dovrebbe essere creato o un'altra azione correlata all'indice che può danneggiare la performance.


3
profilo, profilo, profilo
GrandmasterB

Risposte:


15

Ciò dipende in parte dal motivo per cui il database deve essere utilizzato, poiché in generale gli indici rallentano inserimenti e aggiornamenti e accelerano le query. In un data warehouse, in genere non ci sono aggiornamenti e inserimenti in batch, rendendo più semplice la creazione di indici e molte e molte query, che vengono velocizzate con molti indici. In un database online per le vendite sul web e simili, ci sono molti inserti e aggiornamenti, quindi avere più di alcuni indici accuratamente selezionati lo rallenterà.

Se si ricevono molte query di un tipo specifico, è possibile creare un indice per la query, sebbene ciò sia più per l'elaborazione online che per i data warehouse. Se alcune colonne emergono molto nelle query, potresti volere un indice su quella colonna, e questo è particolarmente utile per i data warehouse, che vengono interrogati in molti modi diversi e spesso imprevedibili.

Ogni volta che aggiungi o rimuovi un indice, prova a fare un test delle prestazioni per vedere quale effetto ha. Senza quello, stai sparando alla cieca.

Esistono libri sull'ottimizzazione di query e database, spesso specifici per un sistema di database e l'utilizzo degli strumenti di RDBMS. Se ti trovi a dover ottimizzare molto il database, tuttavia, stai eseguendo un'operazione di grandi dimensioni e probabilmente dovresti assumere un DBA con le competenze appropriate.


17

Dipende molto da come usi i tuoi tavoli. Non esiste una risposta singola e semplice.

Il miglior consiglio che posso darti è: usa un consulente per il tuning . Analizzeranno i comandi del database mentre si sta utilizzando l'applicazione, quindi eseguiranno test di carico su di essa per fornire consigli significativi.

Esistono per SQL Server e Oracle . Non so se altri DBMS li hanno, solo dubito che non forniscano tali strumenti di base.

Poche raccomandazioni casuali:

  • Gli indici forniscono guadagni ad alte prestazioni quando applicati su colonne spesso inclusi nella clausola WHERE
  • Utilizzare l'indice cluster per la colonna più utilizzata nelle query.
  • Non dimenticare che puoi creare più indici con una combinazione di colonne (poiché sono utilizzati nelle tue query)
  • Avere molti indici riduce le prestazioni dei comandi INSERT.

Ultimo consiglio : se le performance di DB sono davvero importanti per il tuo progetto, assumi uno specialista. È quello che ho fatto.


2
+1 per gli indici su combinazioni di colonne. Indici su colonne ae nonb è uguale a un indice su . Quest'ultimo è quasi buono quanto l'indice attivo per velocizzare le query con una condizione attiva , è enormemente migliore per le query con condizioni attive e non è utile solo per le query . (La maggior parte dei database non lo utilizzerà. Oracle lo farà, ma non ne ricava il chilometraggio che fa regolarmente.)(a, b)aaabb
btilly

2
+1, aggiungerebbe "impara a leggere i piani di query in modo da sapere cosa indicizzare"
Steven A. Lowe,

4

@Pierre 303 lo ha già detto, ma lo dirò di nuovo. DO utilizzare indici su combinazioni di colonne. Un indice combinato attivato (a, b)è solo leggermente più lento per le query arispetto a un indice asolo ed è notevolmente migliore se la query combina entrambe le colonne. Alcuni database possono unire gli indici sopra ae bprima di colpire la tabella, ma questo non è quasi come avere un indice combinato. Quando si crea un indice combinato, è necessario inserire prima la colonna che è più probabile che venga cercata nell'indice combinato.

Se il database lo supporta, NON inserire indici nelle funzioni visualizzate nelle query anziché nelle colonne. (Se stai chiamando una funzione su una colonna, gli indici su quella colonna sono inutili.)

Se si utilizza un database con i veri tabelle temporanee che è possibile creare e distruggere al volo (ad esempio, PostgreSQL, MySQL, ma non Oracle), quindi NON creare indici su tabelle temporanee.

Se si utilizza un database che lo consente (ad es. Oracle), bloccare DO in buoni piani di query. Gli ottimizzatori di query nel tempo modificheranno i piani di query. Di solito migliorano il piano. Ma a volte lo fanno drammaticamente peggio. In genere non noterai davvero miglioramenti del piano: la query non era un collo di bottiglia. Ma un singolo piano negativo può abbattere un sito occupato.

NON avere indici sulle tabelle su cui stai per caricare un grande volume di dati. È molto, molto più veloce eliminare gli indici, caricare i dati, quindi ricostruire gli indici piuttosto che mantenerli mentre si carica la tabella.

NON utilizzare gli indici per le query che devono accedere a più di una piccola parte di una tabella di grandi dimensioni. (Quanto piccolo dipende dall'hardware. Il 5% è una regola empirica decente.) Ad esempio, se si hanno dati con nomi e genere, i nomi sono un buon candidato per l'indicizzazione poiché ogni nome dato rappresenta una piccola frazione delle righe totali. Non sarebbe utile indicizzare il genere poiché dovrai comunque accedere al 50% delle righe. Invece, vuoi davvero utilizzare una scansione completa della tabella. Il motivo è che gli indici finiscono per accedere a un file di grandi dimensioni in modo casuale, causando la necessità di ricerche su disco. Le ricerche su disco sono lente. Ad esempio, recentemente sono riuscito a velocizzare un'interrogazione di un'ora che sembrava:

SELECT small_table.id, SUM(big_table.some_value)
FROM small_table
  JOIN big_table
    ON big_table.small_table_id = small_table.id
GROUP BY small_table.id

a meno di 3 minuti riscrivendolo come segue:

SELECT small_table.id, big_table_summary.summed_value
FROM small_table
  JOIN (
      SELECT small_table_id, SUM(some_value) as summed_value
      FROM big_table
      GROUP BY small_table_id
    ) big_table_summary
    ON big_table_summary.small_table_id =  small_table.id

che ha costretto il database a capire che non dovrebbe tentare di utilizzare l'indice allettante su big_table.small_table_id. (Un buon database, come Oracle, dovrebbe capirlo da solo. Questa query era in esecuzione su MySQL.)

Aggiornamento: ecco una spiegazione del punto di ricerca del disco che ho fatto. Un indice fornisce una rapida occhiata per dire dove sono i dati nella tabella. Di solito si tratta di una vittoria, dato che guarderai solo i dati che devi guardare. Ma non sempre, in particolare se alla fine esaminerai molti dati. I dischi trasmettono bene i dati, ma rallentano le ricerche. Una ricerca casuale di dati su disco richiede 1/200 di secondo. La versione lenta della query finì per fare qualcosa come 600.000 di quelli e impiegò quasi un'ora. (Ha fatto più ricerche di così, ma la cache ha catturato alcune di quelle.) Al contrario, la versione veloce sapeva che doveva leggere tutto e trasmettere i dati in streaming a qualcosa come 70 MB / secondo. Ha superato un tavolo da 11 GB in meno di 3 minuti.


Ciao, sono confuso dal tuo esempio. Avrei pensato che l'uso dell'indice avrebbe reso le cose più veloci, non è questo il punto degli indici? Stai dicendo che se una query accedesse a> 5% di una tabella, avere un indice sulla colonna che stai cercando renderebbe le cose più lente?
Fai clic su Aggiorna

@Click Upvote: se una query accede a più del 5% (frazione esatta altamente dipendente da hardware e dati) di una tabella, è più veloce non utilizzare un indice per quella query. Avere un indice non fa male finché non lo usi. Aggiornerò con maggiori dettagli sul perché.
btilly

Informazioni utili. Maggiori informazioni su questo ad esempio mysqlperformanceblog.com/2007/08/28/… Ma mi chiedevo, "ignorare la chiave" non dipendeva da questo che è necessario renderlo una subquery?
Inca,

@Inca: non ero a conoscenza di 'ignore key'. Cambio database abbastanza che spesso ci sono cose specifiche del database di cui non sono a conoscenza. Dai suoni che avrebbe funzionato, ma significativamente meno efficacemente della mia eventuale soluzione. La differenza è che ciò si unirebbe, quindi raggrupperebbe, mentre il mio raggruppasse, quindi si unì. Ciò consente di risparmiare lavoro sull'unione perché è necessario unire meno record.
btilly

"Un buon database (ad es. Oracle, ma non MySQL)": per favore, evita stupide cose promozionali come quella, specialmente quando ignori il fatto che MySQL può usare perfettamente più indici contemporaneamente (annotato "MERCE INDICE" nei piani di query) .
Patrick Allaert,

2

DO: indicizza i pochissimi campi a cui accedi di più tramite query e / o confronti.

NON: indicizza ogni campo della tabella pensando che lo renderà più veloce.

Non ho statistiche su di esso, ma provo a non contenere più di 4 campi indicizzati in una tabella se posso farne a meno. La normalizzazione dei miei database di solito aiuta a mantenere bassi questi numeri poiché tutto diventa ricercabile con il tasto numerico (che è comunque più veloce). Provo a stare lontano dai campi di testo completo per l'indicizzazione. Sono piuttosto pesanti.


2

Fondamentalmente, gli indici accelerano la ricerca ma rallentano la scrittura e occupano spazio. Questo è il compromesso in corso.

Qualsiasi campo che viene spesso utilizzato per unirsi, cercare / confrontare o ordinare è un candidato per un indice. Sapere che è davvero benefico, misura. Tuttavia, le chiavi esterne delle tabelle pesantemente unite con lotti (> 1000) di record e pochi inserti pagheranno.

Per i campi di testo, è possibile indicizzare su una parte del campo (ad esempio i primi 6 caratteri) che accelererebbe la query ma alleggerirebbe il carico sugli indici. Le ricerche di testo completo (ricerca su like %substring%) richiedono tecniche diverse, che non conosco, quindi non posso darti consigli.

Una situazione importante in cui gli indici non sono utili: non è possibile utilizzare l'indice dei campi di data completa o datetime quando si cerca (/ si unisce / si ordina) in parte della data. Un indice date_createdattivo non ti aiuterà con una query simile select * from t where year(date_created) = 2011. In mysql non puoi creare un indice su parte della data. (Quando si utilizza " between" anziché year()utilizzare l'indice nel campo della data.)

Maggiori informazioni su MYSQL nel manuale: http://dev.mysql.com/doc/refman/5.6/en/optimization-indexes.html


1

DO: prova a ridurre al minimo la dimensione totale dell'indice cluster. Le voci di indice cluster saranno incluse in altri indici non cluster e da qui deriva il potenziale per sprecare spazio su disco.


1

Pensa a una tabella come a un lessico, in cui gli articoli sono ordinati per ordine di apparizione (o nessun ordine utile) e a un indice di tabella come indice di un libro a quel lessico.

Usa un indice per trovare rapidamente qualcosa in un libro. Invece di scansionare l'intero libro, devi solo trovare la chiave nell'indice (un indice di solito in qualche modo ordinato (per categoria, per campo scientifico, per epoca storica, ecc.), Ciò significa anche che non dovrai scansionare l'intero indice) e poi passa alla pagina giusta.

A differenza di un libro, tuttavia, un tavolo non viene stampato una volta e quindi immutabile. Viene aggiornato continuamente, quindi ogni indice deve essere aggiornato con esso. Questo ovviamente ha un costo in termini di spazio e tempo, che può essere giustificato solo dall'utilità di un indice.

Quindi utilizza un indice per una colonna, se quella colonna viene utilizzata come chiave nelle frequenti query di ricerca e non utilizzarne una, in caso contrario. La parola frequente è tanto più quantificabile quanto in generale. Alla fine dovrai fare una buona stima di quelli che sono frequenti, quindi semplicemente benchmarkare le prestazioni con o senza indice in caso di dubbio.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.