2010-07-07 18 views
6

Sembra che tutte le domande relative a questo argomento siano molto specifiche e, mentre apprezzo gli esempi specifici, sono interessato alle basi dell'ottimizzazione SQL. Mi trovo molto bene a lavorare in SQL, e ho un background in hardware/software di basso livello.Come ottimizzare le query in un database - Nozioni di base

Quello che voglio sono gli strumenti sia software tangibile, sia un metodo per guardare i database mysql che guardo su base regolare e sapere qual è la differenza tra gli ordini delle dichiarazioni join e le dichiarazioni where.

Voglio sapere perché un indice aiuta, come, esattamente perché. Voglio sapere in modo specifico cosa succede in modo diverso, e voglio sapere come posso effettivamente guardare a ciò che sta accadendo. Non ho bisogno di uno strumento che rompa ogni passo del mio SQL, voglio solo essere in grado di curiosare e se qualcuno non può dirmi quale colonna indicizzare, sarò in grado di tirar fuori un foglio di carta e entro un certo periodo di tempo essere in grado di venire con le risposte.

I database sono complicati, ma non sono COSÌ complicati, e ci deve essere del materiale eccezionale per imparare le nozioni di base in modo da sapere come trovare le risposte ai problemi di ottimizzazione che si incontrano, anche se potrebbero dare la caccia al risposta esatta su un forum.

Si prega di raccomandare qualche lettura che sia concisa, intuitiva e non abbia paura di scendere ai dadi e ai bulloni di basso livello. Preferisco le risorse gratuite online, ma se una raccomandazione di un libro demolisce la testina che colpisce, prenderei in considerazione l'idea di accettarla.

risposta

6

È necessario eseguire una ricerca per tutte le condizioni e per ogni join ... a condizione. I due funzionano allo stesso modo.

Supponiamo di scrivere

select name 
from customer 
where customerid=37; 

In qualche modo il DBMS deve trovare il record o il record con CustomerID = 37. Se non c'è un indice, l'unico modo per farlo è leggere ogni record nella tabella confrontando il customerid a 37. Anche quando ne trova uno, non ha modo di sapere che ce n'è uno solo, quindi deve continuare a cercare altri.

Se si crea un indice su customerid, il DBMS ha modi per cercare l'indice molto rapidamente. Non è una ricerca sequenziale, ma, a seconda del database, una ricerca binaria o qualche altro metodo efficiente. Esattamente come non importa, accetta che sia molto più veloce del sequenziale. L'indice quindi lo porta direttamente al record o ai record appropriati. Inoltre, se si specifica che l'indice è "univoco", il database sa che ce ne può essere solo uno in modo da non perdere tempo a cercare un secondo. (E il DBMS ti impedirà l'aggiunta di un secondo.)

Ora consideriamo questa query:

select name 
from customer 
where city='Albany' and state='NY'; 

ora abbiamo due condizioni. Se si dispone di un indice su uno solo di questi campi, il DBMS utilizzerà tale indice per trovare un sottoinsieme dei record, quindi li ricerca in sequenza.Ad esempio, se si dispone di un indice su stato, il DBMS troverà rapidamente il primo record per NY, quindi cerca in sequenza cercando city = 'Albany' e smette di cercare quando raggiunge l'ultimo record per NY.

Se si dispone di un indice che include entrambi i campi, ad esempio "creare indice su cliente (stato, città)", il DBMS può immediatamente eseguire lo zoom sui record corretti.

Se si dispone di due indici separati, uno su ciascun campo, il DBMS avrà varie regole a cui si applica per decidere quale indice utilizzare. Di nuovo, esattamente come questo viene fatto dipende dal particolare DBMS che si sta usando, ma fondamentalmente cerca di mantenere le statistiche sul numero totale di record, il numero di valori diversi e la distribuzione dei valori. Quindi cercherà sequenzialmente quei record per quelli che soddisfano l'altra condizione. In questo caso il DBMS probabilmente osserverebbe che ci sono molte più città di quante siano gli stati, quindi usando l'indice della città può rapidamente ingrandire i record di 'Albany'. Quindi cercherà sequenzialmente questi, controllando lo stato di ciascuno contro "NY". Se si dispone di record per Albany, California, questi verranno saltati.

Ogni join richiede una sorta di ricerca.

dire che scriviamo

select customer.name 
from transaction 
join customer on transaction.customerid=customer.customerid 
where transaction.transactiondate='2010-07-04' and customer.type='Q'; 

Ora il DBMS deve decidere quale tabella da leggere prima, selezionare i record appropriati da lì, e poi trovare i record corrispondenti in altra tabella.

Se si dispone di un indice su transaction.transactiondate e customer.customerid, il piano migliore sarebbe probabilmente trovare tutte le transazioni con questa data, quindi per ciascuna di esse trovare il cliente con il customerid corrispondente, quindi verificare che il cliente ha il tipo giusto

Se non si dispone di un indice su customer.customerid, il DBMS potrebbe trovare rapidamente la transazione, ma poi per ogni transazione dovrebbe cercare in sequenza la tabella clienti cercando un customerid corrispondente. (Questo potrebbe essere molto lento.)

Supponiamo invece che gli unici indici presenti siano su transaction.customerid e customer.type. Quindi il DBMS probabilmente userebbe un piano completamente diverso. Probabilmente eseguirà la scansione della tabella clienti per tutti i clienti con il tipo corretto, quindi ognuno di questi trova tutte le transazioni per questo cliente e li ricerca in sequenza per la data corretta.

La chiave più importante per l'ottimizzazione è capire quali indici saranno veramente utili e creare quegli indici. Gli indici extra non utilizzati sono un onere per il database perché richiede lavoro per mantenerli, e se non vengono mai utilizzati questo è uno sforzo inutile.

È possibile indicare quali indici il DBMS utilizzerà per qualsiasi query specificata con il comando EXPLAIN. Lo uso sempre per determinare se le mie query sono ottimizzate bene o se dovrei creare indici aggiuntivi. (Leggi la documentazione su questo comando per una spiegazione del suo output.)

Avvertenza: Ricordare che il DBMS mantiene statistiche sul numero di record e sul numero di valori diversi e così via in ciascuna tabella. EXPLAIN potrebbe darti un piano completamente diverso rispetto a ieri se i dati sono cambiati. Ad esempio, se si dispone di una query che unisce due tabelle e una di queste tabelle è molto piccola mentre l'altra è grande, verrà polarizzata prima di leggere la tabella piccola e quindi trovare i record corrispondenti nella tabella grande. L'aggiunta di record a una tabella può cambiare che è più grande e quindi portare il DBMS a modificare il suo piano. Pertanto, dovresti provare a ESPLORARE contro un database con dati realistici. L'esecuzione su un database di test con 5 record in ogni tabella ha un valore molto inferiore rispetto all'esecuzione su un database attivo.

Bene, c'è molto altro che si può dire, ma non voglio scrivere un libro qui.

+0

Wow, sono molte informazioni, grazie, ho imparato un paio di cose leggendo questo che posso usare immediatamente – walnutmon

7

Diciamo che stai cercando un amico in un'altra città. Un modo sarebbe quello di andare di porta in porta e chiedere se questa è la casa che stai cercando. Un altro modo è quello di guardare la mappa.

L'indice è la mappa di una tabella. Può dire al motore DB esattamente dove è la cosa che stai cercando. Pertanto, indicizzi ogni colonna che pensi di dover cercare e tralascia le colonne di cui stai leggendo solo i dati e che non cercano mai.

Buona lettura tecnica about indices e about ORDER BY optimization. E se vuoi vedere cosa sta succedendo esattamente, vuoi la dichiarazione EXPLAIN.

+1

Inoltre, vale la pena osservare il registro lento di mysql. http://dev.mysql.com/doc/refman/5.0/en/slow-query-log.html – Pete

+0

Mi interessa in particolare il modo in cui gli indici influenzeranno i join, io uso molto il join e non capisco veramente come lavorano a un livello basso. Ad esempio, è importante che tu abbia due colonne indicizzate che possono essere molto grandi l'una sull'altra? In che modo lo spazio per i join viene allocato e attraversato? Cosa succede se sono entrambi indicizzati, cosa succede se nessuno dei due è indicizzato? – walnutmon

+0

Fondamentalmente, l'intero capitolo 7.2 del manuale MySQL è interessante. Se una colonna non è indicizzata, è necessario al massimo n confronti per trovare qualcosa. Se lo è, è necessario al massimo log (n) confronti. La lunghezza del dato è sicuramente un fattore, ma l'indice è più importante. Tuttavia, trovo che non mi unisco quasi mai ai campi non interi. La mia politica è, se ha una possibilità non banale di ripetersi, dovrebbe avere una tabella e una chiave primaria. E "cosa succede se" domande come la tua sono la risposta migliore costruendo il modello ed eseguendo 'EXPLAIN' su query di esempio. – Amadan

2

Non pensare all'ottimizzazione dei database. Pensa all'ottimizzazione delle query.

Generalmente, si ottimizza un caso a scapito di altri. Non vi resta che decidere quali casi che ti interessa.

1

"Sono interessato in particolare nel modo in cui gli indici interesseranno unisce"

Per fare un esempio, mi prendo il caso di equijoin (scegliere tra una , B WHERE Ax = By).

Se non ci sono indici (che è possibile in teoria ma non credo in SQL), in pratica l'unico modo per calcolare il join è prendere l'intera tabella A e dividerla su x, prendere l'intero tabella y e partizionarlo su y, quindi abbinare le partizioni e infine per ogni coppia di partizioni corrispondenti calcolare le righe dei risultati. Questo è costoso (o addirittura assolutamente impossibile a causa delle limitazioni di memoria) per tutti tranne i tavoli più piccoli.

Stessa storia se esistono indici su A e/o B, ma nessuno di essi ha x resp. y come il suo primo attributo.

Se esiste un indice su x, ma non su y (o viceversa), si apre un'altra possibilità: scansione tabella B, per ogni valore di selezione di riga y, cercare quel valore nell'indice e recuperare il corrispondente A righe per calcolare il join.Nota che questo non ti vincerà molto se non si applicano ulteriori restrizioni (AND z = ...) - tranne nel caso in cui ci siano solo poche corrispondenze tra i valori x e y.

Se gli indici ordinati (gli indici basati su hash non sono ordinati) esistono sia su y che su y, allora si apre una terza possibilità: eseguire una scansione corrispondente sugli indici stessi (gli indici stessi rischiano di essere più piccoli delle tabelle da soli, quindi la scansione dell'indice stesso richiederà un tempo più breve), e per i corrispondenti valori x/y, calcolare il join delle righe corrispondenti.

Questa è la linea di base. Variazioni per join su x> y ecc.

1

Non so di strumenti MySql ma in MS SqlServer si dispone di uno strumento che mostra tutte le operazioni che una query richiederebbe e quanto del tempo di elaborazione dell'intero la query avrebbe richiesto.

L'utilizzo di questo strumento mi ha aiutato a capire in che modo le query sono ottimizzate da Query Optimizer molto più di quanto ritengo qualsiasi libro possa essere d'aiuto, perché spesso non è facile capire cosa fa l'ottimizzatore. Modificando la query e possibilmente il database di sottolineatura, ho potuto vedere come ogni modifica influiva sul piano di query. Ci sono alcuni punti chiave nella scrittura di query, ma a me sembra che tu abbia già un'idea di quelli che così ottimizzando nel tuo caso è molto più di questo rispetto a qualsiasi regola generale. Dopo alcuni anni di sviluppo del db, ho esaminato alcuni libri specificamente mirati all'ottimizzazione del database su SQL Server e ho trovato pochissime informazioni utili.

Quick googling ha proposto questo: http://www.mysql.com/products/enterprise/query.html che sembra uno strumento simile.

Questa è stata, naturalmente, su un livello di query, ottimizzazioni a livello di database sono ancora un altro paio di maniche, ma ci si sta guardando parametri come ad esempio la vostra base di dati è divisa sui dischi rigidi, ecc Almeno in SqlServer è possibile selezionare per dividere le tabelle in diversi dischi HDD e anche disco e questo può avere un grande effetto perché le unità e le teste possono funzionare in parallelo. Un altro è il modo in cui è possibile creare le query in modo che il database possa eseguirle in più thread e processori in parallelo, ma entrambi questi problemi dipendono ancora dal motore del database e dalla versione anche in uso.

Problemi correlati