Supervisió del rendiment de les consultes PostgreSQL. Part 1: informes

Enginyer - traduït del llatí - inspirat.
Un enginyer pot fer qualsevol cosa. (c) R. Diesel.
Epígrafs.
Supervisió del rendiment de les consultes PostgreSQL. Part 1: informes
O una història sobre per què un administrador de bases de dades necessita recordar el seu passat de programació.

Prefaci

S'han canviat tots els noms. Els partits són aleatoris. El material és únicament l'opinió personal de l'autor.

Exempció de garanties: a la sèrie d'articles prevista no hi haurà una descripció detallada i precisa de les taules i scripts utilitzats. Els materials no es poden utilitzar immediatament "TAL CUAL".
En primer lloc, a causa de la gran quantitat de material,
en segon lloc, a causa de la nitidesa amb la base de producció d'un client real.
Per tant, als articles només es donaran idees i descripcions en la forma més general.
Potser en el futur el sistema creixerà fins al nivell de publicació a GitHub, o potser no. El temps es mostrarà.

L'inici de la història-Recordes com va començar tot?».
Què va passar com a resultat, en els termes més generals - "La síntesi com un dels mètodes per millorar el rendiment de PostgreSQL»

Per què necessito tot això?

Bé, en primer lloc, per no oblidar-vos de vosaltres mateixos, recordant els dies gloriosos de la jubilació.
En segon lloc, sistematitzar allò escrit. Per a mi mateix, de vegades començo a confondre'm i oblido parts separades.

Bé, i el més important: de sobte pot ser útil per a algú i ajudar a no reinventar la roda i no recollir un rasclet. En altres paraules, milloreu el vostre karma (no Khabrovski). Perquè el més valuós d'aquest món són les idees. El més important és trobar una idea. I traduir la idea en realitat ja és una qüestió purament tècnica.

Així que comencem a poc a poc...

Formulació del problema.

Disponible:

PostgreSQL (10.5), càrrega mixta (OLTP+DSS), càrrega mitjana a lleugera, allotjada al núvol AWS.
No hi ha monitorització de bases de dades, el monitoratge de la infraestructura es presenta com a eines estàndard d'AWS en una configuració mínima.

Es requereix:

Superviseu el rendiment i l'estat de la base de dades, trobeu i tingueu informació inicial per optimitzar les consultes pesades de la base de dades.

Breu introducció o anàlisi de solucions

Per començar, intentem analitzar les opcions per resoldre el problema des del punt de vista d'una anàlisi comparativa dels beneficis i problemes per a l'enginyer, i deixem que aquells que se suposa que estan a la llista de personal s'ocupen dels beneficis i pèrdues. de gestió.

Opció 1: "Treballar sota demanda"

Ho deixem tot tal com està. Si el client no està satisfet amb alguna cosa en la salut, el rendiment de la base de dades o l'aplicació, ho notificarà als enginyers de DBA per correu electrònic o creant una incidència a la taquilla.
Un enginyer, després d'haver rebut una notificació, entendrà el problema, oferirà una solució o arxivarà el problema, amb l'esperança que tot es resolgui per si sol i, de totes maneres, tot s'oblidarà aviat.
Pa de pessic i bunyols, contusions i copsPa de pessic i bunyols:
1. Res addicional a fer
2. Sempre hi ha l'oportunitat de sortir i embrutar-se.
3. Molt temps que pots passar pel teu compte.
Hematomes i cops:
1. Tard o d'hora, el client pensarà en l'essència de l'ésser i la justícia universal en aquest món i tornarà a fer-se la pregunta: per què els pago els meus diners? La conseqüència és sempre la mateixa: l'única pregunta és quan el client s'avorreix i s'acomiada. I l'alimentació està buida. És trist.
2. El desenvolupament d'un enginyer és zero.
3. Dificultats per programar el treball i la càrrega

Opció 2 - "Balla amb panderetes, calçat i calçat"

Paràgraf 1-Per què necessitem un sistema de seguiment, rebrem totes les peticions. Llencem tot tipus de consultes al diccionari de dades i a les vistes dinàmiques, activem tot tipus de comptadors, posem tot en taules, analitzem periòdicament llistes i taules, per dir-ho. Com a resultat, tenim gràfics, taules, informes bonics o poc. El més important - això seria més, més.
Paràgraf 2-Generar activitat-executar l'anàlisi de tot això.
Paràgraf 3-Estem preparant un determinat document, anomenem aquest document, simplement - "com equipem la base de dades".
Paràgraf 4- El client, veient tota aquesta magnificència de gràfics i xifres, es troba en una ingènua confiança infantil: ara tot ens funcionarà, aviat. I, fàcilment i sense dolor, se separen dels seus recursos econòmics. La direcció també està segura que els nostres enginyers estan treballant dur. Càrrega màxima.
Paràgraf 5- Repetiu el pas 1 regularment.
Pa de pessic i bunyols, contusions i copsPa de pessic i bunyols:
1. La vida dels directius i enginyers és senzilla, previsible i plena d'activitat. Tot bull, tothom està ocupat.
2. La vida del client tampoc no és dolenta: sempre està segur que cal tenir una mica de paciència i que tot sortirà bé. No està millorant, bé, bé, aquest món és injust, en la propera vida, tindreu sort.
Hematomes i cops:
1. Tard o d'hora, hi haurà un proveïdor més intel·ligent d'un servei similar que farà el mateix, però una mica més barat. I si el resultat és el mateix, per què pagar més? La qual cosa portarà de nou a la desaparició de l'alimentador.
2. És avorrit. Què avorrit qualsevol activitat poc significativa.
3. Com en la versió anterior, sense desenvolupament. Però per a un enginyer, l'inconvenient és que, a diferència de la primera opció, aquí cal generar constantment un BID. I això requereix temps. Que es pot gastar en benefici del seu ésser estimat. Perquè no pots cuidar-te, tothom es preocupa per tu.

Opció 3-No cal inventar una bicicleta, cal comprar-la i muntar-la.

Els enginyers d'altres empreses mengen pizza amb cervesa a consciència (oh, els temps gloriosos de Sant Petersburg als anys 90). Utilitzem sistemes de monitorització que es fan, es depuren i funcionen i, en general, aporten beneficis (bé, almenys als seus creadors).
Pa de pessic i bunyols, contusions i copsPa de pessic i bunyols:
1. No cal perdre el temps inventant allò que ja està inventat. Agafa i utilitza.
2. Els sistemes de monitoratge no estan escrits per ximples i, per descomptat, són útils.
3. Els sistemes de monitorització en funcionament solen proporcionar informació filtrada útil.
Hematomes i cops:
1. En aquest cas, l'enginyer no és un enginyer, sinó només un usuari del producte d'una altra persona o un usuari.
2. El client ha d'estar convençut de la necessitat de comprar quelcom que en general no vol entendre, i no ho hauria de fer, i en general s'ha aprovat el pressupost de l'any i no canviarà. Aleshores, heu d'assignar un recurs separat, configurar-lo per a un sistema específic. Aquells. Primer cal pagar, pagar i tornar a pagar. I el client és avar. Aquesta és la norma d'aquesta vida.

Què fer, Txernyxevski? La teva pregunta és molt pertinent. (Amb)

En aquest cas particular i en la situació actual, podeu fer una mica diferent: fem el nostre propi sistema de seguiment.
Supervisió del rendiment de les consultes PostgreSQL. Part 1: informes
Bé, no és un sistema, és clar, en el sentit complet de la paraula, això és massa sorollós i presumptuós, però almenys d'alguna manera us ho faciliteu i recolliu més informació per resoldre els incidents de rendiment. Per no trobar-te en una situació: "ves-hi, no sé on, troba això, no sé què".

Quins són els avantatges i els contres d'aquesta opció:

Pros:
1. És interessant. Bé, almenys més interessant que la constant "redueix el fitxer de dades, altera l'espai de taula, etc.".
2. Són noves habilitats i nous desenvolupaments. Que en el futur, tard o d'hora, donaran merescuts pa de pessic i bunyols.
Contres:
1. Cal treballar. Treballar molt.
2. Haureu d'explicar regularment el significat i les perspectives de tota activitat.
3. S'haurà de sacrificar alguna cosa, perquè l'únic recurs de què disposa l'enginyer -el temps- està limitat per l'Univers.
4. El pitjor i el més desagradable - com a resultat, poden sortir escombraries com "No un ratolí, ni una granota, sinó un petit animal desconegut".

Qui no arrisca alguna cosa no beu xampany.
Així que comença la diversió.

Idea general - esquemàtica

Supervisió del rendiment de les consultes PostgreSQL. Part 1: informes
(Il·lustració extreta de l'article «La síntesi com un dels mètodes per millorar el rendiment de PostgreSQL")

Explicació:

  • La base de dades de destinació s'instal·la amb l'extensió estàndard de PostgreSQL "pg_stat_statements".
  • A la base de dades de monitorització, creem un conjunt de taules de servei per emmagatzemar l'historial pg_stat_statements en l'etapa inicial i per configurar mètriques i monitoratge en el futur
  • A l'amfitrió de monitorització, creem un conjunt d'scripts bash, inclosos els per generar incidències al sistema de tickets.

Taules de servei

Per començar, un ERD esquemàticament simplificat, el que va passar al final:
Supervisió del rendiment de les consultes PostgreSQL. Part 1: informes
Breu descripció de les taulespunt final - host, punt de connexió a la instància
database - Opcions de base de dades
pg_stat_history - taula històrica per emmagatzemar instantànies temporals de la vista pg_stat_statements de la base de dades de destinació
glossari_mètric - Diccionari de mètriques de rendiment
metric_config - configuració de mètriques individuals
mètric - una mètrica específica per a la sol·licitud que s'està supervisant
metric_alert_history - Historial d'avisos de rendiment
consulta_log - taula de servei per emmagatzemar registres analitzats del fitxer de registre de PostgreSQL descarregat d'AWS
línia de base - paràmetres del període de temps utilitzat com a base
punt de control - configuració de mètriques per comprovar l'estat de la base de dades
checkpoint_alert_history - Historial d'avís de mètriques de comprovació de l'estat de la base de dades
pg_stat_db_queries — Taula de serveis de peticions actives
registre d'activitats — Taula de servei de registre d'activitats
trap_oide - taula de servei de configuració de trampes

Etapa 1: recopilar estadístiques de rendiment i obtenir informes

S'utilitza una taula per emmagatzemar informació estadística. pg_stat_history
estructura de la taula pg_stat_history

                                          Taula "public.pg_stat_history" Columna | tipus | Modificadors--------------------+--------------------- --+---- -------------------------------- id | enter | no és nul per defecte nextval('pg_stat_history_id_seq'::regclass) snapshot_timestamp | marca de temps sense zona horària | database_id | enter | dbid | oid | ID d'usuari | oid | queryid | bigint | consulta | text | trucades | bigint | temps_total | doble precisió | min_temps | doble precisió | temps_màx | doble precisió | temps_mig | doble precisió | stddev_time | doble precisió | files | bigint | shared_blks_hit | bigint | shared_blks_read | bigint | shared_blks_dirtied | bigint | shared_blks_written | bigint | local_blks_hit | bigint | local_blks_read | bigint | local_blks_dirtied | bigint | local_blks_escrit | bigint | temp_blks_read | bigint | temp_blks_escrit | bigint | temps_de_lectura_blk | doble precisió | blk_write_time | doble precisió | baseline_id | enter | Índexs: "pg_stat_history_pkey" CLAU PRIMÀRIA, btree (id) "database_idx" btree (database_id) "queryid_idx" btree (queryid) "snapshot_timestamp_idx" btree (snapshot_timestamp) Foreign-key-base de dades: restricció de base de dades REFERENCIA_K: base de dades (id ) SOBRE ELIMINAR EN CASCADA

Com podeu veure, la taula és només una vista acumulada de dades pg_stat_statements a la base de dades objectiu.

L'ús d'aquesta taula és molt senzill.

pg_stat_history representarà les estadístiques acumulades d'execució de consultes per a cada hora. Al començament de cada hora, després d'omplir la taula, estadístiques pg_stat_statements restablir amb pg_stat_statements_reset().
Nota: Es recullen estadístiques de sol·licituds amb una durada superior a 1 segon.
Omplint la taula pg_stat_history

--pg_stat_history.sql
CREATE OR REPLACE FUNCTION pg_stat_history( ) RETURNS boolean AS $$
DECLARE
  endpoint_rec record ;
  database_rec record ;
  pg_stat_snapshot record ;
  current_snapshot_timestamp timestamp without time zone;
BEGIN
  current_snapshot_timestamp = date_trunc('minute',now());  
  
  FOR endpoint_rec IN SELECT * FROM endpoint 
  LOOP
    FOR database_rec IN SELECT * FROM database WHERE endpoint_id = endpoint_rec.id 
	  LOOP
	    
		RAISE NOTICE 'NEW SHAPSHOT IS CREATING';
		
		--Connect to the target DB	  
	    EXECUTE 'SELECT dblink_connect(''LINK1'',''host='||endpoint_rec.host||' dbname='||database_rec.name||' user=USER password=PASSWORD '')';
 
        RAISE NOTICE 'host % and dbname % ',endpoint_rec.host,database_rec.name;
		RAISE NOTICE 'Creating snapshot of pg_stat_statements for database %',database_rec.name;
		
		SELECT 
	      *
		INTO 
		  pg_stat_snapshot
	    FROM dblink('LINK1',
	      'SELECT 
	       dbid , SUM(calls),SUM(total_time),SUM(rows) ,SUM(shared_blks_hit) ,SUM(shared_blks_read) ,SUM(shared_blks_dirtied) ,SUM(shared_blks_written) , 
           SUM(local_blks_hit) , SUM(local_blks_read) , SUM(local_blks_dirtied) , SUM(local_blks_written) , SUM(temp_blks_read) , SUM(temp_blks_written) , SUM(blk_read_time) , SUM(blk_write_time)
	       FROM pg_stat_statements WHERE dbid=(SELECT oid from pg_database where datname=current_database() ) 
		   GROUP BY dbid
  	      '
	               )
	      AS t
	       ( dbid oid , calls bigint , 
  	         total_time double precision , 
	         rows bigint , shared_blks_hit bigint , shared_blks_read bigint ,shared_blks_dirtied bigint ,shared_blks_written	 bigint ,
             local_blks_hit	 bigint ,local_blks_read bigint , local_blks_dirtied bigint ,local_blks_written bigint ,
             temp_blks_read	 bigint ,temp_blks_written bigint ,
             blk_read_time double precision , blk_write_time double precision	  
	       );
		 
		INSERT INTO pg_stat_history
          ( 
		    snapshot_timestamp  ,database_id  ,
			dbid , calls  ,total_time ,
            rows ,shared_blks_hit  ,shared_blks_read  ,shared_blks_dirtied  ,shared_blks_written ,local_blks_hit , 	 	
            local_blks_read,local_blks_dirtied,local_blks_written,temp_blks_read,temp_blks_written, 	
            blk_read_time, blk_write_time 
		  )		  
	    VALUES
	      (
	       current_snapshot_timestamp ,
		   database_rec.id ,
	       pg_stat_snapshot.dbid ,pg_stat_snapshot.calls,
	       pg_stat_snapshot.total_time,
	       pg_stat_snapshot.rows ,pg_stat_snapshot.shared_blks_hit ,pg_stat_snapshot.shared_blks_read ,pg_stat_snapshot.shared_blks_dirtied ,pg_stat_snapshot.shared_blks_written , 
           pg_stat_snapshot.local_blks_hit , pg_stat_snapshot.local_blks_read , pg_stat_snapshot.local_blks_dirtied , pg_stat_snapshot.local_blks_written , 
	       pg_stat_snapshot.temp_blks_read , pg_stat_snapshot.temp_blks_written , pg_stat_snapshot.blk_read_time , pg_stat_snapshot.blk_write_time 	   
	      );		   
		  
        RAISE NOTICE 'Creating snapshot of pg_stat_statements for queries with min_time more than 1000ms';
	
        FOR pg_stat_snapshot IN
          --All queries with max_time greater than 1000 ms
	      SELECT 
	        *
	      FROM dblink('LINK1',
	        'SELECT 
	         dbid , userid ,queryid,query,calls,total_time,min_time ,max_time,mean_time, stddev_time ,rows ,shared_blks_hit ,
			 shared_blks_read ,shared_blks_dirtied ,shared_blks_written , 
             local_blks_hit , local_blks_read , local_blks_dirtied , 
			 local_blks_written , temp_blks_read , temp_blks_written , blk_read_time , 
			 blk_write_time
	         FROM pg_stat_statements 
			 WHERE dbid=(SELECT oid from pg_database where datname=current_database() AND min_time >= 1000 ) 
  	        '

	                  )
	        AS t
	         ( dbid oid , userid oid , queryid bigint ,query text , calls bigint , 
  	           total_time double precision ,min_time double precision	 ,max_time double precision	 , mean_time double precision	 ,  stddev_time double precision	 , 
	           rows bigint , shared_blks_hit bigint , shared_blks_read bigint ,shared_blks_dirtied bigint ,shared_blks_written	 bigint ,
               local_blks_hit	 bigint ,local_blks_read bigint , local_blks_dirtied bigint ,local_blks_written bigint ,
               temp_blks_read	 bigint ,temp_blks_written bigint ,
               blk_read_time double precision , blk_write_time double precision	  
	         )
	    LOOP
		  INSERT INTO pg_stat_history
          ( 
		    snapshot_timestamp  ,database_id  ,
			dbid ,userid  , queryid  , query  , calls  ,total_time ,min_time ,max_time ,mean_time ,stddev_time ,
            rows ,shared_blks_hit  ,shared_blks_read  ,shared_blks_dirtied  ,shared_blks_written ,local_blks_hit , 	 	
            local_blks_read,local_blks_dirtied,local_blks_written,temp_blks_read,temp_blks_written, 	
            blk_read_time, blk_write_time 
		  )		  
	      VALUES
	      (
	       current_snapshot_timestamp ,
		   database_rec.id ,
	       pg_stat_snapshot.dbid ,pg_stat_snapshot.userid ,pg_stat_snapshot.queryid,pg_stat_snapshot.query,pg_stat_snapshot.calls,
	       pg_stat_snapshot.total_time,pg_stat_snapshot.min_time ,pg_stat_snapshot.max_time,pg_stat_snapshot.mean_time, pg_stat_snapshot.stddev_time ,
	       pg_stat_snapshot.rows ,pg_stat_snapshot.shared_blks_hit ,pg_stat_snapshot.shared_blks_read ,pg_stat_snapshot.shared_blks_dirtied ,pg_stat_snapshot.shared_blks_written , 
           pg_stat_snapshot.local_blks_hit , pg_stat_snapshot.local_blks_read , pg_stat_snapshot.local_blks_dirtied , pg_stat_snapshot.local_blks_written , 
	       pg_stat_snapshot.temp_blks_read , pg_stat_snapshot.temp_blks_written , pg_stat_snapshot.blk_read_time , pg_stat_snapshot.blk_write_time 	   
	      );
		  
        END LOOP;

        PERFORM dblink_disconnect('LINK1');  
				
	  END LOOP ;--FOR database_rec IN SELECT * FROM database WHERE endpoint_id = endpoint_rec.id 
    
  END LOOP;

RETURN TRUE;  
END
$$ LANGUAGE plpgsql;

Com a resultat, després d'un cert període de temps a la taula pg_stat_history tindrem un conjunt d'instantànies del contingut de la taula pg_stat_statements base de dades objectiu.

De fet, informant

Mitjançant consultes senzilles, podeu obtenir informes força útils i interessants.

Dades agregades per a un període de temps determinat

Sol·licitud

SELECT 
  database_id , 
  SUM(calls) AS calls ,SUM(total_time)  AS total_time ,
  SUM(rows) AS rows , SUM(shared_blks_hit)  AS shared_blks_hit,
  SUM(shared_blks_read) AS shared_blks_read ,
  SUM(shared_blks_dirtied) AS shared_blks_dirtied,
  SUM(shared_blks_written) AS shared_blks_written , 
  SUM(local_blks_hit) AS local_blks_hit , 
  SUM(local_blks_read) AS local_blks_read , 
  SUM(local_blks_dirtied) AS local_blks_dirtied , 
  SUM(local_blks_written)  AS local_blks_written,
  SUM(temp_blks_read) AS temp_blks_read, 
  SUM(temp_blks_written) temp_blks_written , 
  SUM(blk_read_time) AS blk_read_time , 
  SUM(blk_write_time) AS blk_write_time
FROM 
  pg_stat_history
WHERE 
  queryid IS NULL AND
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT
GROUP BY database_id ;

D.B. Temps

to_char(interval '1 mil·lisegon' * pg_total_stat_history_rec.total_time, 'HH24:MI:SS.MS')

Temps d'E/S

to_char(interval '1 mil·lisegon' * ( pg_total_stat_history_rec.blk_read_time + pg_total_stat_history_rec.blk_write_time ), 'HH24:MI:SS.MS')

TOP10 SQL per total_time

Sol·licitud

SELECT 
  queryid , 
  SUM(calls) AS calls ,
  SUM(total_time)  AS total_time  	
FROM 
  pg_stat_history
WHERE 
  queryid IS NOT NULL AND 
  database_id = DATABASE_ID AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT 
GROUP BY queryid 
ORDER BY 3 DESC 
LIMIT 10
-------------------------------------------------- ------------------------------------ | TOP10 SQL PER TEMPS TOTAL D'EXECUCIÓ | #| queryid| trucades| trucades %| temps_total (ms) | dbtime % +----+-----------+-----------+-----------+------ --------------------+----------- | 1| 821760255| 2| .00001|00:03:23.141( 203141.681 ms.)| 5.42 | 2| 4152624390| 2| .00001|00:03:13.929( 193929.215 ms.)| 5.17 | 3| 1484454471| 4| .00001|00:02:09.129( 129129.057 ms.)| 3.44 | 4| 655729273| 1| .00000|00:02:01.869( 121869.981 ms.)| 3.25 | 5| 2460318461| 1| .00000|00:01:33.113( 93113.835 ms.)| 2.48 | 6| 2194493487| 4| .00001|00:00:17.377( 17377.868 ms.)| .46 | 7| 1053044345| 1| .00000|00:00:06.156( 6156.352 ms.)| .16 | 8| 3644780286| 1| .00000|00:00:01.063( 1063.830 ms.)| .03

TOP10 SQL per temps total d'E/S

Sol·licitud

SELECT 
  queryid , 
  SUM(calls) AS calls ,
  SUM(blk_read_time + blk_write_time)  AS io_time
FROM 
  pg_stat_history
WHERE 
  queryid IS NOT NULL AND 
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT
GROUP BY  queryid 
ORDER BY 3 DESC 
LIMIT 10
-------------------------------------------------- -------------------------------------- | TOP10 SQL PER TEMPS TOTAL D'E/S | #| queryid| trucades| trucades %| Temps d'E/S (ms)|db Temps d'E/S % +----+-----------+-----------+------ -----+-------------------------------+------------ -- | 1| 4152624390| 2| .00001|00:08:31.616( 511616.592 ms.)| 31.06 de juny | 2| 821760255| 2| .00001|00:08:27.099( 507099.036 ms.)| 30.78 | 3| 655729273| 1| .00000|00:05:02.209( 302209.137 ms.)| 18.35 | 4| 2460318461| 1| .00000|00:04:05.981( 245981.117 ms.)| 14.93 | 5| 1484454471| 4| .00001|00:00:39.144( 39144.221 ms.)| 2.38 | 6| 2194493487| 4| .00001|00:00:18.182( 18182.816 ms.)| 1.10 | 7| 1053044345| 1| .00000|00:00:16.611( 16611.722 ms.)| 1.01 | 8| 3644780286| 1| .00000|00:00:00.436( 436.205 ms.)| .03

TOP10 SQL per temps màxim d'execució

Sol·licitud

SELECT 
  id AS snapshotid , 
  queryid , 
  snapshot_timestamp ,  
  max_time 
FROM 
  pg_stat_history 
WHERE 
  queryid IS NOT NULL AND 
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT
ORDER BY 4 DESC 
LIMIT 10

-------------------------------------------------- ------------------------------------ | TOP10 SQL PER TEMPS MÀXIM D'EXECUCIÓ | #| instantània| snapshotID| queryid| temps_màx. (ms) +----+------------------+-----------+--------- --+----------------------------------------- | 1| 05.04.2019/01/03 4169:655729273| 00| 02| 01.869:121869.981:2( 04.04.2019 ms.) | 17| 00/4153/821760255 00:01| 41.570| 101570.841| 3:04.04.2019:16( 00 ms.) | 4146| 821760255/00/01 41.570:101570.841| 4| 04.04.2019| 16:00:4144( 4152624390 ms.) | 00| 01/36.964/96964.607 5:04.04.2019| 17| 00| 4151:4152624390:00( 01 ms.) | 36.964| 96964.607/6/05.04.2019 10:00| 4188| 1484454471| 00:01:33.452( 93452.150 ms.) | 7| 04.04.2019/17/00 4150:2460318461 | 00| 01| 33.113:93113.835:8( 04.04.2019 ms.) | 15| 00/4140/1484454471 00:00| 11.892| 11892.302| 9:04.04.2019:16( 00 ms.) | 4145| 1484454471/00/00 11.892:11892.302| 10| 04.04.2019| 17:00:4152( 1484454471 ms.) | 00| 00/11.892/11892.302 XNUMX:XNUMX| XNUMX| XNUMX| XNUMX:XNUMX:XNUMX( XNUMX ms.) | XNUMX| XNUMX/XNUMX/XNUMX XNUMX:XNUMX| XNUMX| XNUMX| XNUMX:XNUMX:XNUMX (XNUMX ms.)

TOP10 SQL per lectura/escriptura del buffer SHARED

Sol·licitud

SELECT 
  id AS snapshotid , 
  queryid ,
  snapshot_timestamp , 
  shared_blks_read , 
  shared_blks_written 
FROM 
  pg_stat_history
WHERE 
  queryid IS NOT NULL AND 
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT AND
  ( shared_blks_read > 0 OR shared_blks_written > 0 )
ORDER BY 4 DESC  , 5 DESC 
LIMIT 10
-------------------------------------------------- ------------------------------------ | TOP10 SQL PER BÚFER COMPARTIT LECTURA/ESCRITURA | #| instantània| snapshotID| queryid| blocs compartits llegir| blocs compartits escriviu +----+------------------+-----------+---------- -+---------------------+--------------------- | 1| 04.04.2019/17/00 4153:821760255| 797308| 0| 2| 04.04.2019 | 16| 00/4146/821760255 797308:0| 3| 05.04.2019| 01| 03 | 4169| 655729273/797158/0 4:04.04.2019| 16| 00| 4144| 4152624390 | 756514| 0/5/04.04.2019 17:00| 4151| 4152624390| 756514| 0 | 6| 04.04.2019/17/00 4150:2460318461| 734117| 0| 7| 04.04.2019 | 17| 00/4155/3644780286 52973:0| 8| 05.04.2019| 01| 03 | 4168| 1053044345/52818/0 9:04.04.2019| 15| 00| 4141| 2194493487 | 52813| 0/10/04.04.2019 16:00| 4147| 2194493487| 52813| 0 | XNUMX| XNUMX/XNUMX/XNUMX XNUMX:XNUMX| XNUMX| XNUMX| XNUMX| XNUMX | XNUMX| XNUMX/XNUMX/XNUMX XNUMX:XNUMX| XNUMX| XNUMX| XNUMX| XNUMX -------------------------------------------------- -------------------------------------------------

Histograma de distribució de consultes per temps màxim d'execució

Sol·licituds

SELECT  
  MIN(max_time) AS hist_min  , 
  MAX(max_time) AS hist_max , 
  (( MAX(max_time) - MIN(min_time) ) / hist_columns ) as hist_width
FROM 
  pg_stat_history 
WHERE 
  queryid IS NOT NULL AND
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT ;

SELECT 
  SUM(calls) AS calls
FROM 
  pg_stat_history 
WHERE 
  queryid IS NOT NULL AND
  database_id =DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT AND 
  ( max_time >= hist_current_min AND  max_time < hist_current_max ) ;
|------------------------------------------------- ----------------------------------------- | MAX_TIME HISTOGRAMA | TOTAL DE TRUCADES : 33851920 | TEMPS MIN : 00:00:01.063 | TEMPS MÀXIM: 00:02:01.869 ---------------------------------- -------- ----------------------------- | durada min| durada màxima| trucades +---------------------------------+-------------- ---------------------+----------- | 00:00:01.063( 1063.830 ms.) | 00:00:13.144( 13144.445 ms.) | 9 | 00:00:13.144( 13144.445 ms.) | 00:00:25.225( 25225.060 ms.) | 0 | 00:00:25.225( 25225.060 ms.) | 00:00:37.305( 37305.675 ms.) | 0 | 00:00:37.305( 37305.675 ms.) | 00:00:49.386( 49386.290 ms.) | 0 | 00:00:49.386( 49386.290 ms.) | 00:01:01.466( 61466.906 ms.) | 0 | 00:01:01.466( 61466.906 ms.) | 00:01:13.547( 73547.521 ms.) | 0 | 00:01:13.547( 73547.521 ms.) | 00:01:25.628( 85628.136 ms.) | 0 | 00:01:25.628( 85628.136 ms.) | 00:01:37.708( 97708.751 ms.) | 4 | 00:01:37.708( 97708.751 ms.) | 00:01:49.789( 109789.366 ms.) | 2 | 00:01:49.789( 109789.366 ms.) | 00:02:01.869( 121869.981 ms.) | 0

TOP10 instantànies per consulta per segon

Sol·licituds

--pg_qps.sql
--Calculate Query Per Second 
CREATE OR REPLACE FUNCTION pg_qps( pg_stat_history_id integer ) RETURNS double precision AS $$
DECLARE
 pg_stat_history_rec record ;
 prev_pg_stat_history_id integer ;
 prev_pg_stat_history_rec record;
 total_seconds double precision ;
 result double precision;
BEGIN 
  result = 0 ;
  
  SELECT *
  INTO pg_stat_history_rec
  FROM 
    pg_stat_history
  WHERE id = pg_stat_history_id ;

  IF pg_stat_history_rec.snapshot_timestamp IS NULL 
  THEN
    RAISE EXCEPTION 'ERROR - Not found pg_stat_history for id = %',pg_stat_history_id;
  END IF ;  
  
 --RAISE NOTICE 'pg_stat_history_id = % , snapshot_timestamp = %', pg_stat_history_id , 
 pg_stat_history_rec.snapshot_timestamp ;
  
  SELECT 
    MAX(id)   
  INTO
    prev_pg_stat_history_id
  FROM
    pg_stat_history
  WHERE 
    database_id = pg_stat_history_rec.database_id AND
	queryid IS NULL AND
	id < pg_stat_history_rec.id ;

  IF prev_pg_stat_history_id IS NULL 
  THEN
    RAISE NOTICE 'Not found previous pg_stat_history shapshot for id = %',pg_stat_history_id;
	RETURN NULL ;
  END IF;
  
  SELECT *
  INTO prev_pg_stat_history_rec
  FROM 
    pg_stat_history
  WHERE id = prev_pg_stat_history_id ;
  
  --RAISE NOTICE 'prev_pg_stat_history_id = % , prev_snapshot_timestamp = %', prev_pg_stat_history_id , prev_pg_stat_history_rec.snapshot_timestamp ;    

  total_seconds = extract(epoch from ( pg_stat_history_rec.snapshot_timestamp - prev_pg_stat_history_rec.snapshot_timestamp ));
  
  --RAISE NOTICE 'total_seconds = % ', total_seconds ;    
  
  --RAISE NOTICE 'calls = % ', pg_stat_history_rec.calls ;      
  
  IF total_seconds > 0 
  THEN
    result = pg_stat_history_rec.calls / total_seconds ;
  ELSE
   result = 0 ; 
  END IF;
   
 RETURN result ;
END
$$ LANGUAGE plpgsql;


SELECT 
  id , 
  snapshot_timestamp ,
  calls , 	
  total_time , 
  ( select pg_qps( id )) AS QPS ,
  blk_read_time ,
  blk_write_time
FROM 
  pg_stat_history
WHERE 
  queryid IS NULL AND 
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT AND
  ( select pg_qps( id )) IS NOT NULL 
ORDER BY 5 DESC 
LIMIT 10
|------------------------------------------------- ----------------------------------------- | TOP10 instantànies ordenades per números de QueryPerSeconds -------------------------------------- ------ ------------------------------------------- ------ -------------------------------------------- | #| instantània| snapshotID| trucades| dbtime total| QPS | Temps d'E/S | Temps d'E/S % +-----+------------------+-----------+------- ----+----------------------------------+----------- -+---------------------------------+----------- | 1| 04.04.2019/20/04 4161:5758631| 00| 06| 30.513:390513.926:1573.396( 00 ms.)| 00| 01.470:1470.110:376 (2 ms.)| .04.04.2019 | 17| 00/4149/3529197 00:11| 48.830| 708830.618| 980.332:00:12( 47.834 ms.)| 767834.052| 108.324:3:04.04.2019( 16 ms.)| 00 | 4143| 3525360/00/10 13.492:613492.351| 979.267| 00| 08:41.396:521396.555( 84.988 ms.)| 4| 04.04.2019:21:03(4163 ms.)| 2781536 | 00| 03/06.470/186470.979 785.745:00| 00| 00.249| 249.865:134:5( 04.04.2019 ms.)| 19| 03:4159:2890362 (00 ms.)| .03 | 16.784| 196784.755/776.979/00 00:01.441| 1441.386| 732| 6:04.04.2019:14( 00 ms.)| 4137| 2397326:00:04( 43.033 ms.)| .283033.854 | 665.924| 00/00/00.024 24.505:009 | 7| 04.04.2019| 15:00:4139(2394416 ms.)| 00| 04:51.435:291435.010( 665.116 ms.)| .00 | 00| 12.025/12025.895/4.126 8:04.04.2019| 13| 00| 4135:2373043:00(04 ms.)| 26.791| 266791.988:659.179:00( 00 ms.)| 00.064 | 64.261| 024/9/05.04.2019 01:03| 4167| 4387191| 00:06:51.380( 411380.293 ms.)| 609.332| 00:05:18.847( 318847.407 ms.)| .77.507 | 10| 04.04.2019/18/01 4157:1145596| 00| 01| 19.217:79217.372:313.004( 00 ms.)| 00| 01.319:1319.676:1.666( XNUMX ms.)| XNUMX | XNUMX| XNUMX/XNUMX/XNUMX XNUMX:XNUMX| XNUMX| XNUMX| XNUMX:XNUMX:XNUMX(XNUMX ms.)| XNUMX| XNUMX:XNUMX:XNUMX (XNUMX ms.)| XNUMX

Historial d'execucions horàries amb QueryPerSeconds i temps d'E/S

Sol·licitud

SELECT 
  id , 
  snapshot_timestamp ,
  calls , 	
  total_time , 
  ( select pg_qps( id )) AS QPS ,
  blk_read_time ,
  blk_write_time
FROM 
  pg_stat_history
WHERE 
  queryid IS NULL AND 
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT
ORDER BY 2
|-----------------------------------------------------------------------------------------------
| HOURLY EXECUTION HISTORY  WITH QueryPerSeconds and I/O Time
-----------------------------------------------------------------------------------------------------------------------------------------------
| QUERY PER SECOND HISTORY
|    #|          snapshot| snapshotID|      calls|                      total dbtime|        QPS|                          I/O time| I/O time %
+-----+------------------+-----------+-----------+----------------------------------+-----------+----------------------------------+-----------
|    1|  04.04.2019 11:00|       4131|       3747|  00:00:00.835(       835.374 ms.)|      1.041|  00:00:00.000(          .000 ms.)|       .000
|    2|  04.04.2019 12:00|       4133|    1002722|  00:01:52.419(    112419.376 ms.)|    278.534|  00:00:00.149(       149.105 ms.)|       .133
|    3|  04.04.2019 13:00|       4135|    2373043|  00:04:26.791(    266791.988 ms.)|    659.179|  00:00:00.064(        64.261 ms.)|       .024
|    4|  04.04.2019 14:00|       4137|    2397326|  00:04:43.033(    283033.854 ms.)|    665.924|  00:00:00.024(        24.505 ms.)|       .009
|    5|  04.04.2019 15:00|       4139|    2394416|  00:04:51.435(    291435.010 ms.)|    665.116|  00:00:12.025(     12025.895 ms.)|      4.126
|    6|  04.04.2019 16:00|       4143|    3525360|  00:10:13.492(    613492.351 ms.)|    979.267|  00:08:41.396(    521396.555 ms.)|     84.988
|    7|  04.04.2019 17:00|       4149|    3529197|  00:11:48.830(    708830.618 ms.)|    980.332|  00:12:47.834(    767834.052 ms.)|    108.324
|    8|  04.04.2019 18:01|       4157|    1145596|  00:01:19.217(     79217.372 ms.)|    313.004|  00:00:01.319(      1319.676 ms.)|      1.666
|    9|  04.04.2019 19:03|       4159|    2890362|  00:03:16.784(    196784.755 ms.)|    776.979|  00:00:01.441(      1441.386 ms.)|       .732
|   10|  04.04.2019 20:04|       4161|    5758631|  00:06:30.513(    390513.926 ms.)|   1573.396|  00:00:01.470(      1470.110 ms.)|       .376
|   11|  04.04.2019 21:03|       4163|    2781536|  00:03:06.470(    186470.979 ms.)|    785.745|  00:00:00.249(       249.865 ms.)|       .134
|   12|  04.04.2019 23:03|       4165|    1443155|  00:01:34.467(     94467.539 ms.)|    200.438|  00:00:00.015(        15.287 ms.)|       .016
|   13|  05.04.2019 01:03|       4167|    4387191|  00:06:51.380(    411380.293 ms.)|    609.332|  00:05:18.847(    318847.407 ms.)|     77.507
|   14|  05.04.2019 02:03|       4171|     189852|  00:00:10.989(     10989.899 ms.)|     52.737|  00:00:00.539(       539.110 ms.)|      4.906
|   15|  05.04.2019 03:01|       4173|       3627|  00:00:00.103(       103.000 ms.)|      1.042|  00:00:00.004(         4.131 ms.)|      4.010
|   16|  05.04.2019 04:00|       4175|       3627|  00:00:00.085(        85.235 ms.)|      1.025|  00:00:00.003(         3.811 ms.)|      4.471
|   17|  05.04.2019 05:00|       4177|       3747|  00:00:00.849(       849.454 ms.)|      1.041|  00:00:00.006(         6.124 ms.)|       .721
|   18|  05.04.2019 06:00|       4179|       3747|  00:00:00.849(       849.561 ms.)|      1.041|  00:00:00.000(          .051 ms.)|       .006
|   19|  05.04.2019 07:00|       4181|       3747|  00:00:00.839(       839.416 ms.)|      1.041|  00:00:00.000(          .062 ms.)|       .007
|   20|  05.04.2019 08:00|       4183|       3747|  00:00:00.846(       846.382 ms.)|      1.041|  00:00:00.000(          .007 ms.)|       .001
|   21|  05.04.2019 09:00|       4185|       3747|  00:00:00.855(       855.426 ms.)|      1.041|  00:00:00.000(          .065 ms.)|       .008
|   22|  05.04.2019 10:00|       4187|       3797|  00:01:40.150(    100150.165 ms.)|      1.055|  00:00:21.845(     21845.217 ms.)|     21.812

Text de totes les seleccions SQL

Sol·licitud

SELECT 
  queryid , 
  query 
FROM 
  pg_stat_history
WHERE 
  queryid IS NOT NULL AND 
  database_id = DATABASE_ID  AND
  snapshot_timestamp BETWEEN BEGIN_TIMEPOINT AND END_TIMEPOINT
GROUP BY queryid , query

Total

Com podeu veure, per mitjans bastant senzills, podeu obtenir molta informació útil sobre la càrrega de treball i l'estat de la base de dades.

Nota:Si arregleu el queryid a les consultes, obtindrem l'historial d'una sol·licitud independent (per tal d'estalviar espai, s'ometen els informes d'una sol·licitud independent).

Així, les dades estadístiques sobre el rendiment de les consultes estan disponibles i es recullen.
S'ha completat la primera etapa "recollida de dades estadístiques".

Podeu passar a la segona etapa: "Configuració de mètriques de rendiment".
Supervisió del rendiment de les consultes PostgreSQL. Part 1: informes

Però aquesta és una història completament diferent.

Continuar ...

Font: www.habr.com

Afegeix comentari