Identificare i componenti di elaborazione delle query
Esistono quattro fasi separate per l'esecuzione della query. Nell'ordine di esecuzione queste fasi sono:
- Analisi
- Trasformazione (Riscrittore)
- Pianificazione
- Esecuzione
Parser
Il parser è responsabile del controllo della stringa di query per la sintassi valida. Il parser ha due parti principali:
- gram.y è costituito da un set di regole grammaticali e azioni corrispondenti.
- scan.1 il lexer, che riconosce gli identificatori e le parole chiave SQL. Ogni parola chiave o identificatore attiva un token creato e consegnato al parser.
Il parser compila un albero di query, che separa la query in parti identificabili per comprendere quali tabelle sono coinvolte, quali filtri sono stati applicati e così via. Le parti di un albero di query sono:
- tipo di comando - SELECT, INSERT, UPDATE o DELETE.
-
voce di tabella range (RTE): elenco di relazioni, tabelle
ie
, sottoquery, risultati di join e così via. In un'istruzione SELECT questi elementi vengono visualizzati dopo la parola chiave FROM. - relazione risultato: la relazione dei risultati per i comandi INSERT, UPDATE e DELETE è la tabella o la vista in cui vengono applicate le modifiche.
- elenco di destinazione: i risultati della query, identificati tra le parole chiave SELECT e FROM. I comandi DELETE non producono un risultato, quindi lo strumento di pianificazione aggiunge una voce speciale per consentire all'executor di trovare la riga da eliminare. I comandi INSERT identificano le nuove righe che devono essere inserite nella relazione dei risultati. Per i comandi UPDATE, l'elenco di destinazione descrive le nuove righe che devono sostituire quelle precedenti.
- qualifica : valore booleano che specifica se l'operazione per la riga del risultato finale deve essere eseguita o meno. Corrisponde alla clausola WHERE di un'istruzione SQL.
- Albero Join - questo albero potrebbe essere un elenco degli elementi FROM. I join possono essere eseguiti in qualsiasi ordine o in un ordine specifico, come gli outer join.
- Altri: elementi non pertinenti in questa fase, ad esempio la clausola ORDER BY.
Riscrittore
L'output del parser viene passato al processo di trasformazione o rewriter, a meno che non venga trovato un errore, nel caso in cui viene restituito un messaggio di errore.
Il riscrittore di query riscrive il testo della query applicando le regole . Il rewriter prende in considerazione le regole e quindi passa la query modificata al Query Planner. La sicurezza a livello di riga viene implementata in questa fase.
Ad esempio, le regole in SELECT vengono sempre applicate come ultimo passaggio, tra cui per le query INSERT, UPDATE e DELETE. Le regole indicano anche che le query UPDATE non sovrascrivono le righe esistenti, ma viene inserita una nuova riga e la riga precedente è nascosta. Dopo il commit della transazione, il processo vacuum può rimuovere la riga nascosta.
Pianificatore
Il compito del pianificatore consiste nell'interpretare le regole della query e comprendere quale tra i diversi modi in cui può essere eseguita la query sia il più veloce.
Lo strumento di pianificazione crea un albero dei piani, con nodi che rappresentano operazioni fisiche sui dati.
PostgreSQL usa query optimizer basato sui costi per trovare il piano ottimale per una query. Lo strumento di pianificazione valuta vari piani di esecuzione e stima la quantità di risorse necessarie, ad esempio cicli cpu, operazioni di I/O e così via. Questa stima viene quindi convertita in unità, nota come costo del piano di . Viene selezionato il piano con il costo più basso.
Tuttavia, man mano che aumenta il numero di join, il numero di possibili piani aumenta in modo esponenziale. La valutazione di ogni possibile piano diventa impossibile anche per query relativamente semplici. L'euristica e gli algoritmi vengono usati per limitare il numero di possibili piani. Il risultato è che il piano selezionato potrebbe non essere il piano ottimale. Tuttavia, è quasi ottimale e viene selezionato in un tempo ragionevole.
Il costo è la stima migliore del pianificatore. Lo scopo della stima dei costi è confrontare piani di esecuzione diversi per la stessa query di nella stessa condizioni di. Lo strumento di pianificazione usa le statistiche raccolte su tabelle e righe per produrre stime dei costi per le query. Affinché le stime dei costi siano accurate, le statistiche devono essere aggiornate.
Statistiche aggiornate
Il componente planner di Query Optimizer usa statistiche su tabelle e righe per produrre stime accurate dei costi.
ANALYZE raccoglie statistiche sulle tabelle di database e archivia i risultati nel catalogo di sistema pg_statistic. È necessario eseguire ANALYZE, se:
- Hai disabilitato autovacuum (che in genere analizza automaticamente le tabelle)
- Hai disabilitato autovacuume non hai eseguito ANALYZE di recente.
- Una delle due istruzioni precedenti o ci sono molte istruzioni INSERT, UPDATE o DELETE.
Le stime dei costi si basano su statistiche up-to-date, e se le statistiche non sono aggiornate, potrebbe essere scelto un piano inefficiente. Quando non viene passato alcun parametro a ANALYZE, ogni tabella del database viene esaminata.
La sintassi per ANALYZE è:
ANALYZE [ VERBOSE ] [ ***table*** [ ( ***column*** [, ...] ) ] ]
VERBOSE visualizza i messaggi di stato per mostrare la tabella da analizzare, insieme ad alcune statistiche.
Pianificare VACUUM e ANALYZE per l'esecuzione giornaliera durante un periodo di utilizzo ridotto. ANALYZE può essere eseguito in parallelo con altre attività perché richiede solo un blocco di lettura sulla tabella di destinazione.
Esecutore
Questa fase accetta il piano creato dallo strumento di pianificazione e lo elabora in modo ricorsivo per estrarre il set di righe richiesto. Ogni volta che un nodo di piano viene chiamato, l'executor deve recapitare una riga o segnalare che è terminato.
L'executor valuta tutti e quattro i tipi di query SQL:
- SELEZIONA
- INSERIRE
- AGGIORNARE
- CANCELLARE
Per SELECT, l'executor restituisce ogni riga al client come set di risultati.
Per INSERT, ogni riga restituita viene inserita nella tabella specificata. Questa attività viene eseguita in un nodo di piano di primo livello speciale denominato ModifyTable.
Per UPDATE, ogni riga calcolata include tutti i valori di colonna aggiornati, oltre all'ID riga della riga di destinazione. I dati vengono inviati a un nodo ModifyTable, che crea una riga aggiornata e contrassegna la riga precedente come eliminata.
Per DELETE, l'unica colonna che il piano restituisce è l'ID della riga. Il nodo ModifyTable usa l'ID riga per contrassegnare la riga come eliminata.