Monitorare le prestazioni con Query Store
SI APPLICA A: Database di Azure per PostgreSQL - Server flessibile
Query Store è una funzionalità di Database di Azure per PostgreSQL server flessibile che consente di tenere traccia delle prestazioni delle query nel tempo. Query Store semplifica la risoluzione dei problemi di prestazioni consentendo di trovare rapidamente le query con esecuzione più lunga e a elevato utilizzo di risorse. Query Store acquisisce automaticamente una cronologia di query e statistiche di runtime e le mantiene per la revisione. Seziona i dati in base al tempo in modo che sia possibile visualizzare i modelli di utilizzo temporali. I dati per tutti gli utenti, i database e le query vengono archiviati in un database denominato azure_sys
nell'istanza del server flessibile Database di Azure per PostgreSQL.
Abilitare l'archivio query
Query Store è disponibile per l'uso senza costi aggiuntivi. Si tratta di una funzionalità di consenso esplicito, quindi non è abilitata per impostazione predefinita in un server. È possibile abilitare o disabilitare Query Store a livello globale per tutti i database in un determinato server e non può essere attivato o disattivato in base al database.
Importante
Non abilitare Query Store nel piano tariffario Burstable perché causerebbe un impatto sulle prestazioni.
Abilitare l'archivio query in portale di Azure
- Accedere al portale di Azure e selezionare il Database di Azure per il server flessibile PostgreSQL.
- Selezionare Parametri del server nella sezione Impostazioni del menu.
- Cercare il
pg_qs.query_capture_mode
parametro. - Impostare il valore su
top
oall
, a seconda che si desideri tenere traccia delle query di primo livello o anche delle query annidate (quelle eseguite all'interno di una funzione o di una routine) e selezionare Salva. Attendere fino a 20 minuti prima che il primo batch di dati sia persistente nelazure_sys
database.
Abilitare il campionamento di attesa dell'archivio query
- Cercare il
pgms_wait_sampling.query_capture_mode
parametro. - Impostare il valore su
all
e selezionare Salva.
Informazioni nell'archivio query
Query Store è costituito da due archivi:
- Un archivio delle statistiche di runtime per il salvataggio permanente delle informazioni delle statistiche di esecuzione delle query.
- Un archivio delle statistiche di attesa per il salvataggio permanente delle informazioni delle statistiche di attesa.
Gli scenari comuni per l'uso di Query Store includono:
- Determinazione del numero di volte in cui una query è stata eseguita in un determinato intervallo di tempo.
- Confronto tra il tempo medio di esecuzione di una query nelle finestre temporali per visualizzare variazioni di grandi dimensioni.
- Identificazione delle query con il tempo di esecuzione più lungo nelle ultime ore.
- Identificazione delle prime N query in attesa delle risorse.
- Informazioni sulla natura delle attese per una determinata query.
Per ridurre al minimo l'utilizzo di spazio, le statistiche di esecuzione di runtime nell'archivio delle statistiche di runtime vengono aggregate per un intervallo di tempo fisso configurabile. È possibile eseguire query sulle informazioni contenute in questi archivi usando le viste.
Accedere alle informazioni sull'archivio query
I dati dell'archivio query vengono archiviati nel database nell'istanza azure_sys
del server flessibile Database di Azure per PostgreSQL.
La query seguente restituisce informazioni sulle query registrate nell'archivio query:
SELECT * FROM query_store.qs_view;
Questa query restituisce informazioni sulle statistiche di attesa:
SELECT * FROM query_store.pgms_wait_sampling_view;
Ricercare query in relazione all'attesa
I tipi di eventi di attesa combinano diversi eventi di attesa in bucket in base alla somiglianza. Query Store fornisce il tipo di evento di attesa, il nome dell'evento di attesa specifico e la query in questione. La possibilità di correlare queste informazioni sulle attese alle statistiche di runtime delle query consente di comprendere in modo più approfondito ciò che contribuisce alle caratteristiche di prestazioni delle query.
Ecco alcuni esempi di come ottenere altre informazioni dettagliate sul carico di lavoro usando le statistiche di attesa in Query Store:
Osservazione | Azione |
---|---|
Attese di blocco elevate | Controllare il testo delle query interessate e identificare le entità di destinazione. Cercare nell'archivio query altre query che vengono eseguite di frequente e/o hanno una durata elevata e stanno modificando la stessa entità. Dopo aver identificato tali query, valutare la possibilità di modificare la logica dell'applicazione per migliorare la concorrenza o usare un livello di isolamento meno restrittivo. |
Attese di I/O con buffer elevato | Trovare le query con un numero elevato di letture fisiche nell'archivio query. Se corrispondono alle query con attese di I/O elevate, è consigliabile abilitare la funzionalità di ottimizzazione automatica degli indici per verificare se è possibile creare alcuni indici che potrebbero ridurre il numero di letture fisiche per tali query. |
Attese di memoria elevate | Trovare le prime query che utilizzano la memoria nell'archivio query. Queste query probabilmente ritardano l'avanzamento delle query interessate. |
Opzioni di configurazione
Quando query store è abilitato, salva i dati nelle finestre di aggregazione di lunghezza determinate dal parametro server pg_qs.interval_length_minutes (il valore predefinito è 15 minuti). Per ogni finestra, archivia fino a 500 query distinte per finestra. Gli attributi che distinguono l'univocità di ogni query sono user_id (identificatore dell'utente che esegue la query), db_id (identificatore del database nel cui contesto viene eseguita la query) e query_id (un valore intero che identifica in modo univoco la query eseguita). Se il numero di query distinte raggiunge il 500 durante l'intervallo configurato, il 5% di quelli registrati viene deallocato per fare più spazio. Quelli deallocati per primi sono quelli che sono stati eseguiti il minor numero di volte.
Per la configurazione dei parametri di Query Store sono disponibili le opzioni seguenti:
Parametro | Descrizione | Default | Intervallo |
---|---|---|---|
pg_qs.interval_length_minutes (*) |
Intervallo di acquisizione in minuti per Query Store. Definisce la frequenza di persistenza dei dati. | 15 |
1 - 30 |
pg_qs.is_enabled_fs |
Solo uso interno: questo parametro viene usato come opzione di override di una funzionalità. Se viene visualizzato come disattivato, Query Store è disabilitato, nonostante il valore impostato per pg_qs.query_capture_mode . |
on |
on , off |
pg_qs.max_plan_size |
Numero massimo di byte salvati dal testo del piano di query dall'archivio query; piani più lunghi vengono troncati. | 7500 |
100 - 10000 |
pg_qs.max_query_text_length |
Lunghezza massima della query che può essere salvata; le query più lunghe vengono troncate. | 6000 |
100 - 10000 |
pg_qs.parameters_capture_mode |
Indica se e quando acquisire parametri posizionali della query. | capture_parameterless_only |
capture_parameterless_only , capture_first_sample |
pg_qs.query_capture_mode |
Istruzioni da tenere traccia. | none |
none , top , all |
pg_qs.retention_period_in_days |
Periodo di conservazione in giorni per Query Store. I dati meno recenti vengono eliminati automaticamente. | 7 |
1 - 30 |
pg_qs.store_query_plans |
Indica se i piani di query devono essere salvati in Query Store. | off |
on , off |
pg_qs.track_utility |
Indica se l'archivio query deve tenere traccia dei comandi dell'utilità. | on |
on , off |
(*) Parametro del server statico che richiede un riavvio del server per rendere effettiva una modifica del relativo valore.
Le opzioni seguenti si applicano specificamente alle statistiche di attesa:
Parametro | Descrizione | Default | Intervallo |
---|---|---|---|
pgms_wait_sampling.history_period |
Frequenza, in millisecondi, in cui vengono campionati gli eventi di attesa. | 100 |
1 - 600000 |
pgms_wait_sampling.is_enabled_fs |
Solo uso interno: questo parametro viene usato come opzione di override di una funzionalità. Se viene visualizzato come off , il campionamento di attesa è disabilitato nonostante il valore impostato per pgms_wait_sampling.query_capture_mode . |
on |
on , off |
pgms_wait_sampling.query_capture_mode |
Quali istruzioni devono tenere traccia dell'estensione pgms_wait_sampling . |
none |
none , all |
Nota
pg_qs.query_capture_mode
pgms_wait_sampling.query_capture_mode
sostituisce . Se pg_qs.query_capture_mode
è none
, l'impostazione pgms_wait_sampling.query_capture_mode
non ha alcun effetto.
Usare il portale di Azure per ottenere o impostare un valore diverso per un parametro.
Viste e funzioni
È possibile eseguire query sulle informazioni registrate dall'archivio query e eliminarle usando alcune viste e funzioni disponibili nello query_store
schema del azure_sys
database. Chiunque nel ruolo pubblico PostgreSQL può usare queste viste per visualizzare i dati nell'archivio query. e sono disponibili solo nel database azure_sys.
Le query vengono normalizzate esaminando la struttura e ignorando qualsiasi elemento non semanticamente significativo, ad esempio valori letterali, costanti, alias o differenze nella combinazione di maiuscole e minuscole.
Se due query sono semanticamente identiche, anche se usano alias diversi per le stesse colonne e tabelle a cui si fa riferimento, vengono identificate con lo stesso query_id. Se due query differiscono solo nei valori letterali usati, vengono identificate anche con lo stesso query_id. Per le query identificate con lo stesso query_id, il relativo sql_query_text è quello della query eseguita per la prima volta dall'avvio dell'attività di registrazione dell'archivio query o dall'ultima volta che i dati persistenti sono stati eliminati perché è stata eseguita la funzione query_store.qs_reset .
Funzionamento della normalizzazione delle query
Di seguito sono riportati alcuni esempi per provare a illustrare il funzionamento di questa normalizzazione:
Si supponga di creare una tabella con l'istruzione seguente:
create table tableOne (columnOne int, columnTwo int);
È possibile abilitare la raccolta dati di Query Store e permettere a uno o più utenti di eseguire le query seguenti, in questo ordine esatto:
select * from tableOne;
select columnOne, columnTwo from tableOne;
select columnOne as c1, columnTwo as c2 from tableOne as t1;
select columnOne as "column one", columnTwo as "column two" from tableOne as "table one";
Tutte le query precedenti condividono lo stesso query_id. Il testo mantenuto da Query Store è quello della prima query eseguita dopo l'abilitazione della raccolta dati. Pertanto, sarebbe select * from tableOne;
.
Il set di query seguente, una volta normalizzato, non corrisponde al set di query precedente perché la clausola WHERE le rende semanticamente diverse:
select columnOne as c1, columnTwo as c2 from tableOne as t1 where columnOne = 1 and columnTwo = 1;
select * from tableOne where columnOne = -3 and columnTwo = -3;
select columnOne, columnTwo from tableOne where columnOne = '5' and columnTwo = '5';
select columnOne as "column one", columnTwo as "column two" from tableOne as "table one" where columnOne = 7 and columnTwo = 7;
Tuttavia, tutte le query in questo ultimo set condividono lo stesso query_id e il testo usato per identificarli tutti è quello della prima query nel batch select columnOne as c1, columnTwo as c2 from tableOne as t1 where columnOne = 1 and columnTwo = 1;
.
Infine, trovare di seguito alcune query che non corrispondono al query_id di quelle del batch precedente e il motivo per cui non corrispondono:
Query:
select columnTwo as c2, columnOne as c1 from tableOne as t1 where columnOne = 1 and columnTwo = 1;
Motivo della mancata corrispondenza: l'elenco di colonne fa riferimento alle stesse due colonne (columnOne e ColumnTwo), ma l'ordine in cui viene fatto riferimento viene invertito, dal columnOne, ColumnTwo
batch precedente a ColumnTwo, columnOne
in questa query.
Query:
select * from tableOne where columnTwo = 25 and columnOne = 25;
Motivo della mancata corrispondenza: l'ordine in cui viene fatto riferimento alle espressioni valutate nella clausola WHERE viene invertito da columnOne = ? and ColumnTwo = ?
nel batch precedente a ColumnTwo = ? and columnOne = ?
in questa query.
Query:
select abs(columnOne), columnTwo from tableOne where columnOne = 12 and columnTwo = 21;
Motivo della mancata corrispondenza: la prima espressione nell'elenco di colonne non columnOne
è più, ma la funzione abs
valutata su columnOne
(abs(columnOne)
), che non è semanticamente equivalente.
Query:
select columnOne as "column one", columnTwo as "column two" from tableOne as "table one" where columnOne = ceiling(16) and columnTwo = 16;
Motivo della mancata corrispondenza: la prima espressione nella clausola WHERE non valuta più l'uguaglianza di columnOne
con un valore letterale, ma con il risultato della funzione ceiling
valutata su un valore letterale, che non è semanticamente equivalente.
Visualizzazioni
query_store.qs_view
Questa vista restituisce tutti i dati salvati in modo permanente nelle tabelle di supporto dell'archivio query. I dati che registrano ancora in memoria per l'intervallo di tempo attualmente attivo, non sono visibili fino a quando l'intervallo di tempo non termina e i relativi dati volatili in memoria vengono raccolti e salvati in modo permanente nelle tabelle archiviate su disco. Questa vista restituisce una riga diversa per ogni database (db_id), utente (user_id) e query (query_id) distinti.
Nome | Type | Riferimenti | Descrizione |
---|---|---|---|
runtime_stats_entry_id |
bigint | ID nella tabella runtime_stats_entries. | |
user_id |
oid | pg_authid.oid | OID dell'utente che ha eseguito l'istruzione. |
db_id |
oid | pg_database.oid | OID del database in cui l'istruzione è stata eseguita. |
query_id |
bigint | Codice hash interno, calcolato dall'albero di analisi dell'istruzione. | |
query_sql_text |
varchar(10000) | Testo di un'istruzione rappresentativa. Query diverse con la stessa struttura vengono raggruppate e questo è il testo per la prima query del gruppo. Il valore predefinito per la lunghezza massima del testo della query è 6000 e può essere modificato usando il parametro dell'archivio query pg_qs.max_query_text_length . Se il testo della query supera questo valore massimo, viene troncato ai primi pg_qs.max_query_text_length caratteri. |
|
plan_id |
bigint | ID del piano corrispondente alla query. | |
start_time |
timestamp | Le query vengono aggregate in base alle finestre temporali. Il parametro pg_qs.interval_length_minutes del server definisce l'intervallo di tempo di tali finestre (il valore predefinito è 15 minuti). Questa colonna corrisponde all'ora di inizio della finestra in cui è stata registrata questa voce. |
|
end_time |
timestamp | Ora di fine corrispondente all'intervallo di tempo per questa voce. | |
calls |
bigint | Numero di volte in cui la query viene eseguita in questo intervallo di tempo. Si noti che per le query parallele, il numero di chiamate per ogni esecuzione corrisponde a 1 per il processo back-end che determina l'esecuzione della query, oltre a molte altre unità per ogni processo di lavoro back-end che avvia per collaborare all'esecuzione dei rami paralleli dell'albero di esecuzione. | |
total_time |
double precision | Tempo totale di esecuzione della query, in millisecondi. | |
min_time |
double precision | Tempo minimo di esecuzione della query, in millisecondi. | |
max_time |
double precision | Tempo massimo di esecuzione della query, in millisecondi. | |
mean_time |
double precision | Tempo medio di esecuzione della query, in millisecondi. | |
stddev_time |
double precision | Deviazione standard del tempo di esecuzione della query, in millisecondi. | |
rows |
bigint | Numero totale di righe recuperate o interessate dall'istruzione. Si noti che per le query parallele, il numero di righe per ogni esecuzione corrisponde al numero di righe restituite al client dal processo back-end che determina l'esecuzione della query, più la somma di tutte le righe avviate per collaborare all'esecuzione dei rami paralleli dell'albero di esecuzione, restituisce al processo back-end che determina l'esecuzione della query. | |
shared_blks_hit |
bigint | Numero totale di riscontri nella cache dei blocchi condivisi ottenuto dall'istruzione. | |
shared_blks_read |
bigint | Numero totale dei blocchi condivisi letti dall'istruzione. | |
shared_blks_dirtied |
bigint | Numero totale dei blocchi condivisi modificati ma non salvati dall'istruzione. | |
shared_blks_written |
bigint | Numero totale di blocchi condivisi scritti dall'istruzione. | |
local_blks_hit |
bigint | Numero totale di riscontri nella cache dei blocchi locali ottenuto dall'istruzione. | |
local_blks_read |
bigint | Numero totale dei blocchi locali letti dall'istruzione. | |
local_blks_dirtied |
bigint | Numero totale dei blocchi locali modificati ma non salvati dall'istruzione. | |
local_blks_written |
bigint | Numero totale di blocchi locali scritti dall'istruzione. | |
temp_blks_read |
bigint | Numero totale dei blocchi temporanei letti dall'istruzione. | |
temp_blks_written |
bigint | Numero totale dei blocchi temporanei scritti dall'istruzione. | |
blk_read_time |
double precision | Tempo totale impiegato dall'istruzione per la lettura dei blocchi, in millisecondi (se il parametro track_io_timing è abilitato, in caso contrario è zero). | |
blk_write_time |
double precision | Tempo totale impiegato dall'istruzione per la scrittura dei blocchi, in millisecondi (se il parametro track_io_timing è abilitato, in caso contrario è zero). | |
is_system_query |
boolean | Determina se il ruolo con user_id = 10 (azuresu) ha eseguito la query. L'utente dispone di privilegi avanzati e viene usato per eseguire operazioni del piano di controllo. Poiché questo è un servizio PaaS gestito, solo Microsoft fa parte del ruolo utente con privilegi avanzati. | |
query_type |
Testo | Tipo di operazione rappresentata dalla query. I valori possibili sono i seguenti: unknown , select , update , insert , delete , merge , utility , nothing , undefined . |
|
search_path |
Testo | Valore di search_path impostato al momento dell'acquisizione della query. | |
query_parameters |
Testo | Rappresentazione testuale di un oggetto JSON con i valori passati ai parametri posizionali di una query con parametri. Questa colonna popola solo il valore in due casi: 1) per le query non con parametri. 2) Per le query con parametri, quando pg_qs.parameters_capture_mode è impostato su capture_first_sample e se Query Store può recuperare i valori per i parametri della query in fase di esecuzione. |
|
parameters_capture_status |
Testo | Tipo di operazione rappresentata dalla query. I valori possibili sono succeeded (la query non è stata parametrizzata o era una query con parametri e i valori sono stati acquisiti correttamente), disabled (la query è stata parametrizzata ma i parametri non sono stati acquisiti perché pg_qs.parameters_capture_mode è stato impostato su capture_parameterless_only ), too_long_to_capture (la query è stata parametrizzata, ma i parametri non sono stati acquisiti perché la lunghezza del json risultante che verrebbe visualizzata nella query_parameters colonna di questa visualizzazione, è stata considerata eccessivamente lunga per la persistenza dell'archivio query), too_many_to_capture (la query è stata parametrizzata, ma i parametri non sono stati acquisiti perché il numero totale di parametri, sono stati considerati eccessivi per la persistenza dell'archivio query), serialization_failed (la query è stata parametrizzata, ma almeno uno dei valori passati come parametro non poteva essere serializzato in testo). |
query_store.query_texts_view
Questa vista restituisce i dati del testo delle query in Query Store. È presente una riga per ogni query_sql_text distinto.
Nome | Tipo | Descrizione |
---|---|---|
query_text_id |
bigint | ID della tabella query_texts |
query_sql_text |
varchar(10000) | Testo di un'istruzione rappresentativa. Query diverse con la stessa struttura vengono raggruppate e questo è il testo per la prima query del gruppo. |
query_type |
smallint | Tipo di operazione rappresentata dalla query. Nella versione di PostgreSQL <= 14, i valori possibili sono 0 (sconosciuto), 1 (selezione), 2 (aggiornamento), 3 (inserimento), 4 (eliminazione), 5 (utilità), 6 (niente). Nella versione di PostgreSQL >= 15, i valori possibili sono 0 (sconosciuto), 1 (selezione), 2 (aggiornamento), 3 (inserimento), 4 (eliminazione), 5 (merge), 6 (utilità), 7 (niente). |
query_store.pgms_wait_sampling_view
Questa vista restituisce i dati degli eventi di attesa in Query Store. Questa vista restituisce una riga diversa per ogni database (db_id), utente (user_id), query (query_id) ed evento (event) distinti.
Nome | Type | Riferimenti | Descrizione |
---|---|---|---|
start_time |
timestamp | Le query vengono aggregate in base alle finestre temporali. Il parametro pg_qs.interval_length_minutes del server definisce l'intervallo di tempo di tali finestre (il valore predefinito è 15 minuti). Questa colonna corrisponde all'ora di inizio della finestra in cui è stata registrata questa voce. |
|
end_time |
timestamp | Ora di fine corrispondente all'intervallo di tempo per questa voce. | |
user_id |
oid | pg_authid.oid | Identificatore di oggetto dell'utente che ha eseguito l'istruzione. |
db_id |
oid | pg_database.oid | Identificatore di oggetto del database in cui è stata eseguita l'istruzione. |
query_id |
bigint | Codice hash interno, calcolato dall'albero di analisi dell'istruzione. | |
event_type |
Testo | Tipo di evento atteso dal back-end. | |
event |
Testo | Nome dell'evento di attesa, se il back-end è attualmente in attesa. | |
calls |
integer | Numero di volte in cui è stato acquisito lo stesso evento. |
Nota
Per un elenco dei valori possibili nelle event_type
colonne e event
della query_store.pgms_wait_sampling_view
vista, vedere la documentazione ufficiale di pg_stat_activity e cercare le informazioni che fanno riferimento alle colonne con gli stessi nomi.
query_store.query_plans_view
Questa vista restituisce il piano di query utilizzato per eseguire una query. È presente una riga per ogni ID di database distinto e un ID di query. Query Store registra solo i piani di query per le query non di utilità.
Nome | Type | Riferimenti | Descrizione |
---|---|---|---|
plan_id |
bigint | Valore hash del piano di query normalizzato generato da EXPLAIN. È in formato normalizzato perché esclude i costi stimati dei nodi del piano e l'utilizzo dei buffer. | |
db_id |
oid | pg_database.oid | OID del database in cui l'istruzione è stata eseguita. |
query_id |
bigint | Codice hash interno, calcolato dall'albero di analisi dell'istruzione. | |
plan_text |
varchar(10000) | Piano di esecuzione dell'istruzione given costs=false, buffers=false e format=text. Output identico a quello prodotto da EXPLAIN. |
Funzioni
query_store.qs_reset
Questa funzione elimina tutte le statistiche raccolte finora dall'archivio query. Elimina le statistiche per le finestre temporali già chiuse, che sono già persistenti nelle tabelle su disco. Elimina anche le statistiche per l'intervallo di tempo corrente, che esistono solo in memoria. Solo i membri del ruolo di amministratore del server (azure_pg_admin
) possono eseguire questa funzione.
query_store.staging_data_reset
Questa funzione elimina tutte le statistiche raccolte in memoria dall'archivio query, ovvero i dati in memoria non ancora scaricati nelle tabelle disco che supportano la persistenza dei dati raccolti per Query Store. Solo i membri del ruolo di amministratore del server (azure_pg_admin
) possono eseguire questa funzione.
Modalità di sola lettura
Quando un'istanza di Database di Azure per PostgreSQL server flessibile è in modalità di sola lettura, ad esempio quando il default_transaction_read_only
parametro è impostato su on
o se la modalità di sola lettura viene abilitata automaticamente a causa del raggiungimento della capacità di archiviazione, Query Store non acquisisce dati.
L'abilitazione dell'archivio query in un server con repliche in lettura non abilita automaticamente query store in una delle repliche di lettura. Anche se la si abilita in una delle repliche in lettura, Query Store non registra le query eseguite su repliche di lettura, perché operano in modalità di sola lettura fino a quando non vengono alzate di livello a primario.