Ottimizzazione degli statement SQL in Oracle

Il linguaggio SQL e' apparentemente molto semplice. Tuttavia per sfruttare appieno le possibilita' che offre e' necessario conoscerne profondamente le particolarita' e gli elementi specifici che ogni diversa implementazione presenta.

Oracle in particolare offre diverse estensioni del linguaggio SQL che comprendono nuove clausole e funzioni di utilita'. Anche dal punto di vista del miglioramento delle prestazioni gli ottimizzatori presenti (RULE BASED e COST BASED che utilizzano diversi parametri di controllo) offrono parecchie funzionalita'.

Un elenco, non esaustivo, di suggerimenti per l'utilizzo dell'SQL e' il seguente:

  Un corretto disegno della base dati e' fondamentale per ottenere buone prestazioni.
Una base dati utilizzata per la reportistica richiede un disegno differente da una base dati utilizzata per le transazioni.

  E' opportuno evitare statement generici quali "SELECT * FROM ..." poiche' Oracle necessita di scansioni ulteriori delle tabelle del data-dictionary (per altro tali statement non sono indipendenti da eventuali modifiche della base dati).

  E' necessario controllare se e' presente un indice Oracle per ogni condizione significativa negli statement SQL che coinvolga una notevole quantita' di dati (tra le condizioni di maggior rilievo vanno ricordati i joins).

  E' necessario controllare che gli indici utili non siano disattivati (vedere piu' avanti come e' possibile disattivare un indice).

  Le tabelle vanno poste in ordine di grandezza (RULE BASED).

  Le condizioni vanno poste in ordine di selettivita' (RULE BASED). Tra le condizioni di maggior selettivita' vi sono i join.

  Evitare operazioni SQL su grandi quantita' di dati e senza condizioni. Non basare la selettivita' delle operazioni sulle sole scelte utente se non in casi particolari. Condizioni come BETWEEN, LIKE, .. non sono generalmente sufficientemente selettive. In particolare un LIKE '%...' impedisce l'utilizzo dell'indice.

  E' opportuno disattivare tutti gli indici non opportuni (RULE BASED)! Per disattivare un indice e' sufficiente applicare una funzione di qualsiasi tipo o effettuare una qualsiasi operazione (come trucco si utilizza una operazione invariante quale +0 o ||'') sul campo dell'indice. Per l'individuazione degli indici non opportuni e' possibile adottare regole empiriche (regola del 10%) o effettuare test sull'accesso ai dati.

  E' necessario effettuare con frequenza l'ANALYZE delle tabelle (ogni volta che avvengono cambiamenti significative sulle dimensioni delle tabelle) (COST BASED).

  Non cercare di effettuare join con loop annidati ma utilizzare le specifiche condizioni.

  Non effettuare elaborazioni statistiche con cicli su tutti i dati ma sfruttare le funzioni di gruppo offerte (peraltro standard).

  Non e' obbligatorio utilizzare la tabella DUAL per determinare l'ora di sistema ma e' possibile utilizzare una selezione differente e gia' richiamata.

  Non e' necessario passare sempre dati su host variables ma e' possibile utilizzare le funzioni offerte dall'RDBMS per le necessarie elaborazioni o conversioni dei dati.

  E' necessario porre attenzione alle clausole NOT in quanto Oracle ritiene che una condizione in NOT sia poco selettiva. E' spesso opportuno valutare selezioni alternative.

  E' necessario porre attenzione alle clausole in OR possono rendere poco selettive le ricerche. In alcuni casi possono essere sostituite con la clausola UNION ALL.

  I valori posti a null richiedono un corretto trattamento sia per la semantica dello statement SQL che per la sua ottimizzazione. Se ben definiti i valori a null consentono risparmi nella scrittura di codice ed efficienza nell'esecuzione, in caso contrario sono inefficienti. Vi sono specifiche funzioni per il trattamento dei valori a null (nvl()).

  Le operazioni di outer join sono relativamente complesse e trattate con modalita' necessariamente differenti dai join comuni. E' in genere sconsigliato l'utilizzo di outer joins sia per motivi di portabilita' che di efficienza.

  E' spesso possibile utilizzare alcune delle potenti funzioni Oracle (decode, conversioni, ..) per ottenere risposte altrimenti complesse.

  Debbono essere attentamente valutate le selezioni annidate; in alcuni casi la forma di selezione annidata e' maggiormente performante, in altri casi e' opportuno effettuare trasformazioni. E' importante notare che tutte le selezioni possono essere trasformate in selezioni annidate (in genere meno efficienti).

  In alcuni casi puo' essere utile sfruttare l'istruzione di union (per formare l'unione insiemistica dei risultati di due differenti selezioni).

  Gli indici composti (costruiti su piu' colonne) vengono usati solo se le colonne che li compongono sono richiamate nello statement SQL nell'ordine corretto: solo la prima, la prima + la seconda, la prima + la seconda + la terza, ecc. Se e' richiamata solo la seconda colonna e non la prima, l'indice composto non viene utilizzato. La corretta definizione di indici composti puo' portare ad una notevole efficienza nelle ricerche.

  Evitare operazioni che richiedano ingenti spazi temporanei per l'esecuzione (ordinamenti di tabelle molto grandi, ..). Le clausole di DISTINCT e di GROUP BY sono analoghe (da punto di vista computazionale) alla clausola di ORDER BY. Lo stesso tipo di problema puo' presentarsi alla creazione di indici.

  Controllare la gestione dei lock per evitare blocchi ai dati su accessi in contemporanea.

  Possono essere costruite condizioni di selezione molto complesse ed efficienti per gli statement di DELETE, INSERT ed UPDATE utilizzando le selezioni annidate.

  Evitare transazioni di lunga durata.

  Evitare transazioni troppo brevi.

  Gli statement SQL hanno un costo (tale costo e' evidente nelle operazioni molto frequenti e di veloce esecuzione). Tale aspetto deve essere tenuto in conto. In generale e' opportuno limitare il numero di statement SQL.

  Per la cancellazione di tutti i record di una tabella e' opportuno l'utilizzo del comando TRUNCATE (dalla versione 7).

  Per la cancellazione per data di un grande numero di record di una tabella il partizionamento ed il relativo comando TRUNCATE sono molto efficienti (dalla versione 8).

Per elementi di maggior dettaglio sui punti presentati e' necessario fare riferimento alla specifica manualistica.

Explain Plan

Il comando EXPLAIN PLAN FOR mostra l'esatto percorso compiuto dall'ottimizzatore ORACLE per eseguire uno statement SQL: e' cosi' possibile verificare se vengono adeguatamente sfruttati gli indici presenti.

Il comando EXPLAIN PLAN, applicato a un determinato statement SQL, popola una tavola di servizio da cui e' possibile estrarre tutte le informazioni sull'esecuzione dello statement. Di default la tabella e' chiamata plan_table. Il report @?/rdbms/admin/utlxpls richiamabile da SQL*Plus fornisce tutti i dettagli del piano di esecuzione della query.


Testo: Ottimizzazione degli statement SQL
Data: 27 Maggio 1997
Versione: 1.0.5 - 1 Aprile 1999
Autore: mail@meo.bogliolo.name