Continuazione dell'articolo ««.
Nell'articolo verrà esaminato e mostrato, attraverso richieste specifiche e esempi, quali informazioni utili si possano ottenere dalla visualizzazione pg_locks.
Avviso.
A causa della novità dell'argomento e della conclusione non ancora conclusa del periodo di test, l'articolo potrebbe contenere errori. Critiche e commenti sono benvenuti e attesi.
Dati di input
Storia della visualizzazione pg_locks
archive_locking
CREATE TABLE archive_locking
( timepoint timestamp senza fuso orario ,
locktype text ,
relation oid ,
mode text ,
tid xid ,
vtid text ,
pid integer ,
blocking_pids integer[] ,
granted boolean ,
queryid bigint
);In sostanza, la tabella è analoga alla tabella archive_pg_stat_activity, descritta più dettagliatamente qui — e qui —
Per popolari la colonna queryid si utilizza la funzione
update_history_locking_by_queryid
--update_history_locking_by_queryid.sql
CREATE OR REPLACE FUNCTION update_history_locking_by_queryid() RETURNS boolean AS $$
DECLARE
result boolean ;
current_minute double precision ;
start_minute integer ;
finish_minute integer ;
start_period timestamp senza fuso orario ;
finish_period timestamp senza fuso orario ;
lock_rec record ;
endpoint_rec record ;
current_hour_diff double precision ;
BEGIN
RAISE NOTICE '***update_history_locking_by_queryid';
result = TRUE ;
current_minute = extract ( minute from now() );
SELECT * FROM endpoint WHERE is_need_monitoring
INTO endpoint_rec ;
current_hour_diff = endpoint_rec.hour_diff ;
IF current_minute < 5
THEN
RAISE NOTICE 'L'orario attuale è inferiore a 5 minuti.';
start_period = date_trunc('hour',now()) + (current_hour_diff * interval '1 hour');
finish_period = start_period - interval '5 minute' ;
ELSE
finish_minute = extract ( minute from now() ) / 5 ;
start_minute = finish_minute - 1 ;
start_period = date_trunc('hour',now()) + interval '1 minute'*start_minute*5+(current_hour_diff * interval '1 hour');
finish_period = date_trunc('hour',now()) + interval '1 minute'*finish_minute*5+(current_hour_diff * interval '1 hour') ;
END IF ;
RAISE NOTICE 'start_period = %', start_period;
RAISE NOTICE 'finish_period = %', finish_period;
FOR lock_rec IN
WITH act_queryid AS
(
SELECT
pid ,
timepoint ,
query_start AS started ,
MAX(timepoint) OVER (PARTITION BY pid , query_start ) AS finished ,
queryid
FROM
activity_hist.history_pg_stat_activity
WHERE
timepoint BETWEEN start_period and
finish_period
GROUP BY
pid ,
timepoint ,
query_start ,
queryid
),
lock_pids AS
(
SELECT
hl.pid ,
hl.locktype ,
hl.mode ,
hl.timepoint ,
MIN ( timepoint ) OVER (PARTITION BY pid , locktype ,mode ) as started
FROM
activity_hist.history_locking hl
WHERE
hl.timepoint between start_period and
finish_period
GROUP BY
hl.pid ,
hl.locktype ,
hl.mode ,
hl.timepoint
)
SELECT
lp.pid ,
lp.locktype ,
lp.mode ,
lp.timepoint ,
aq.queryid
FROM lock_pids lp LEFT OUTER JOIN act_queryid aq ON ( lp.pid = aq.pid AND lp.started BETWEEN aq.started AND aq.finished )
WHERE aq.queryid IS NOT NULL
GROUP BY
lp.pid ,
lp.locktype ,
lp.mode ,
lp.timepoint ,
aq.queryid
LOOP
UPDATE activity_hist.history_locking SET queryid = lock_rec.queryid
WHERE pid = lock_rec.pid AND locktype = lock_rec.locktype AND mode = lock_rec.mode AND timepoint = lock_rec.timepoint ;
END LOOP;
RETURN result ;
END
$$ LANGUAGE plpgsql;Spiegazione: Il valore della colonna queryid viene aggiornato nella tabella history_locking e successivamente, quando viene creata una nuova sezione per la tabella archive_locking, il valore verrà mantenuto nei valori storici.
Uscita
Informazioni generali sui processi in generale.
ATTENDA PER BLOCCHI PER TIPI DI BLOCCO
Query
CON
t AS
(
SELECT
locktype ,
mode ,
count(*) as total
FROM
activity_hist.archive_locking
WHERE
timepoint between pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND
NOT granted
GROUP BY
locktype ,
mode
)
SELECT
locktype ,
mode ,
total * interval '1 second' as duration
FROM t
ORDER BY 3 DESC Esempio
| IN ATTESA DI BLOCCO PER TIPO DI BLOCCO +--------------------+------------------------------+-------------------- | tipo di blocco| modalità| durata +--------------------+------------------------------+-------------------- | transactionid| ShareLock| 19:39:26 | tuple| AccessExclusiveLock| 00:03:35 +--------------------+------------------------------+--------------------
PRELIEVI DI BLOCCO PER TIPO DI BLOCCO
Query
CON
t AS
(
SELECT
tipo_di_blocco,
modalità,
count(*) AS totale
FROM
activity_hist.archive_locking
WHERE
timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND pg_stat_history_end+(current_hour_diff * interval '1 hour') AND
concesso
GROUP BY
tipo_di_blocco,
modalità
)
SELECT
tipo_di_blocco,
modalità,
totale * interval '1 second' AS durata
FROM t
ORDER BY 3 DESC Esempio
| PRELIEVI DI BLOCCO PER TIPO DI BLOCCO +--------------------+------------------------------+-------------------- | tipo di blocco| modalità| durata +--------------------+------------------------------+-------------------- | relazione| RowExclusiveLock| 51:11:10 | virtualxid| ExclusiveLock| 48:10:43 | transactionid| ExclusiveLock| 44:24:53 | relazione| AccessShareLock| 20:06:13 | tuple| AccessExclusiveLock| 17:58:47 | tuple| ExclusiveLock| 01:40:41 | relazione| ShareUpdateExclusiveLock| 00:26:41 | oggetto| RowExclusiveLock| 00:00:01 | transactionid| ShareLock| 00:00:01 | estendere| ExclusiveLock| 00:00:01 +--------------------+------------------------------+--------------------
Informazioni dettagliate sui singoli queryid delle richieste
IN ATTESA DI BLOCCO PER TIPO DI BLOCCO PER QUERYID
Query
CON
lt AS
(
SELECT
pid,
tipo_di_blocco,
modalità,
timepoint,
queryid,
blocking_pids,
MIN(timepoint) OVER (PARTITION BY pid, tipo_di_blocco, modalità) AS iniziato
FROM
activity_hist.archive_locking
WHERE
timepoint BETWEEN pg_stat_history_begin+(current_hour_diff * interval '1 hour') AND
pg_stat_history_end+(current_hour_diff * interval '1 hour') AND
NON concesso AND
queryid IS NOT NULL
GROUP BY
pid,
tipo_di_blocco,
modalità,
timepoint,
queryid,
blocking_pids
)
SELECT
lt.pid,
lt.tipo_di_blocco,
lt.modalità,
lt.iniziato,
lt.queryid,
lt.blocking_pids,
COUNT(*) * interval '1 second' AS durata
FROM lt
GROUP BY
lt.pid,
lt.tipo_di_blocco,
lt.modalità,
lt.iniziato,
lt.queryid,
lt.blocking_pids
ORDER BY 4Esempio
| IN ATTESA DI BLOCCO PER TIPO DI BLOCCO PER QUERYID
+----------+-------------------------+--------------------+------------------------------+--------------------+--------------------+--------------------
| pid| locktype| mode| started| queryid| blocking_pids| duration
+----------+-------------------------+--------------------+------------------------------+--------------------+--------------------+--------------------
| 11288| transactionid| ShareLock| 2019-09-17 10:00:00.302936| 389015618226997618| {11092}| 00:03:34
| 11626| transactionid| ShareLock| 2019-09-17 10:00:21.380921| 389015618226997618| {12380}| 00:00:29
| 11626| transactionid| ShareLock| 2019-09-17 10:00:21.380921| 389015618226997618| {11092}| 00:03:25
| 11626| transactionid| ShareLock| 2019-09-17 10:00:21.380921| 389015618226997618| {12213}| 00:01:55
| 11626| transactionid| ShareLock| 2019-09-17 10:00:21.380921| 389015618226997618| {12751}| 00:00:01
| 11629| transactionid| ShareLock| 2019-09-17 10:00:24.331935| 389015618226997618| {11092}| 00:03:22
| 11629| transactionid| ShareLock| 2019-09-17 10:00:24.331935| 389015618226997618| {12007}| 00:00:01
| 12007| transactionid| ShareLock| 2019-09-17 10:05:03.327933| 389015618226997618| {11629}| 00:00:13
| 12007| transactionid| ShareLock| 2019-09-17 10:05:03.327933| 389015618226997618| {11092}| 00:01:10
| 12007| transactionid| ShareLock| 2019-09-17 10:05:03.327933| 389015618226997618| {11288}| 00:00:05
| 12213| transactionid| ShareLock| 2019-09-17 10:06:07.328019| 389015618226997618| {12007}| 00:00:10PRENDENDO BLOCCO PER TIPO DI BLOCCO PER QUERYID
Query
CON
lt COME
(
SELEZIONA
pid ,
locktype ,
mode ,
timepoint ,
queryid ,
blocking_pids ,
MIN ( timepoint ) OVER (PARTITION BY pid , locktype ,mode ) as started
DA
activity_hist.archive_locking
DOVE
timepoint tra pg_stat_history_begin+(current_hour_diff * interval '1 hour') E
pg_stat_history_end+(current_hour_diff * interval '1 hour') E
concesso E
queryid IS NOT NULL
GRUPPA PER
pid ,
locktype ,
mode ,
timepoint ,
queryid ,
blocking_pids
)
SELEZIONA
lt.pid ,
lt.locktype ,
lt.mode ,
lt.started ,
lt.queryid ,
lt.blocking_pids ,
COUNT(*) * interval '1 second' come duration
DA lt
GRUPPA PER
lt.pid ,
lt.locktype ,
lt.mode ,
lt.started ,
lt.queryid ,
lt.blocking_pids
ORDINA PER 4Esempio
| OTTENERE LOCK DA LOCKTYPES PER QUERYID
+----------+-------------------------+--------------------+------------------------------+--------------------+--------------------+--------------------
| pid| locktype| mode| started| queryid| blocking_pids| duration
+----------+-------------------------+--------------------+------------------------------+--------------------+--------------------+--------------------
| 11288| relation| RowExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {11092}| 00:03:34
| 11092| transactionid| ExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {}| 00:03:34
| 11288| relation| RowExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {}| 00:00:10
| 11092| relation| RowExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {}| 00:03:34
| 11092| virtualxid| ExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {}| 00:03:34
| 11288| virtualxid| ExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {11092}| 00:03:34
| 11288| transactionid| ExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {11092}| 00:03:34
| 11288| tuple| AccessExclusiveLock| 2019-09-17 10:00:00.302936| 389015618226997618| {11092}| 00:03:34Utilizzo della cronologia delle blocchi nell'analisi degli incidenti di performance.
- La richiesta con queryid=389015618226997618 eseguita dal processo con pid=11288 ha atteso un blocco a partire dal 2019-09-17 10:00:00 per 3 minuti.
- Il blocco era mantenuto dal processo con pid=11092.
- Il processo con pid=11092, eseguendo la richiesta con queryid=389015618226997618 a partire dal 2019-09-17 10:00:00, ha mantenuto il blocco per 3 minuti.
Risultato
Ora, spero, inizia la parte più interessante e utile: la raccolta di statistiche e l'analisi dei casi sulla cronologia delle attese e delle blocchi.
In prospettiva, spero di poter ottenere un insieme di note simili a quelle del metadato di Oracle.
In effetti, proprio per questo motivo la metodologia utilizzata viene presentata il più rapidamente possibile per una diffusione generale.
Nel più breve tempo possibile cercherò di pubblicare il progetto su github.
Fonte: habr.com
