Monitoramos sessões ativas do PostgreSQL 10, como no Oracle

imagem

Essa ferramenta foi criada para fins esportivos quando descobri que a visualização pg_stat_activity no PostgreSQL 10 possui os campos wait_event_type e wait_event, que são muito similares em essência à wait_class e ao evento da sessão v $.

Trabalhando ativamente com o programa ASH-Viewer da akardapolov no momento, fiquei curioso para saber como é difícil reescrever esse produto no Postgres. Dado que eu não sou um desenvolvedor profissional, não foi fácil, mas muito interessante. No processo, até achei, ao que me parece, alguns bugs significativos que aparecem no programa original do Oracle e também na Standard Edition.

Os princípios do PASH-Viewer:


Não são necessárias extensões. Nós coletamos dados exclusivamente da visualização pg_stat_activity incorporada.

Uma vez por segundo, é feita uma solicitação para sessões ativas:

texto da solicitação pg_stat_activity
SELECT current_timestamp, datname, pid, usesysid, usename, application_name, backend_type, coalesce(client_hostname, client_addr::text, 'localhost') as client_hostname, wait_event_type, wait_event, query, query_start, 1000 * EXTRACT(EPOCH FROM (clock_timestamp()-query_start)) as duration from pg_stat_activity where state='active' and pid != pg_backend_pid(); 

Uma vez a cada 15 segundos, os dados das últimas 15 imagens são calculados em média e exibidos em um gráfico.

O id SQL necessário para agrupar as consultas na seção Top SQL, eu me gero, não tem nada a ver com o queryid de pg_stat_statements. Eu estava pensando em como usar o queryid, mas infelizmente não encontrei uma maneira de corresponder às consultas desses dois modos de exibição. Seria ótimo se os desenvolvedores adicionassem o campo queryid a pg_stat_activity.

ID SQL = 13 primeiros caracteres do MD5 (texto de consulta normalizado).

Um texto de consulta normalizado é uma consulta na qual os caracteres de nova linha e os espaços extras são removidos e os literais são substituídos por $ 1, $ 2, etc. ... Era difícil escrever uma boa função de normalização de consulta. Eu escrevi uma má. Cito o texto, mas, por favor, não olhe para ele, caso contrário, tenho vergonha. Melhor enviar uma boa.

NormalizeSQL
 public static String NormalizeSQL(String sql) { sql = sql.replaceAll("\\n", " "); sql = sql.replaceAll("\\(", " ( "); sql = sql.replaceAll("\\)", " ) "); sql = sql.replaceAll(",", " , "); sql = sql.replaceAll("'", " ' "); sql = sql.replaceAll("=", " = "); sql = sql.replaceAll("<", " < "); sql = sql.replaceAll(">", " > "); sql = sql.replaceAll(";", ""); sql = sql.replaceAll("[ ]+", " "); sql = sql.replaceAll("> =", ">="); sql = sql.replaceAll("< =", "<="); sql = sql.toLowerCase().trim(); String[] array = sql.split(" ", -1); int var_number = 0; String normalized_sql = ""; Boolean quote_flag = false; for (int i = 0; i < array.length; i++) { if (array[i].equals("'")) { if (!quote_flag) { quote_flag = true; var_number++; normalized_sql += "$" + var_number + " "; } else { quote_flag = false; } } else if (quote_flag) { continue; } else if (array[i].matches("-?\\d+(\\.\\d+)?")) { var_number++; normalized_sql += "$" + var_number + " "; } else if (array[i].equals("order")) { for (int j = i; j < array.length; j++) { normalized_sql += array[j] + " "; } return normalized_sql.trim(); } else { normalized_sql += array[i] + " "; } } return normalized_sql.trim(); } 

Foi difícil concluir o plano de execução da consulta. É para a Oracle que você vem e diz: "Dê-me um plano para sqlid = ...", e ele responde: "Você tem o mais recente, ou ontem, ou mostra tudo do último mês com estatísticas de execução para cada um?" E o PostgreSQL responde você - "O que é sqlid?".

Portanto, para consultas no formato SELECT / UPDATE / INSERT / DELETE, enviamos o comando EXPLAIN ao banco de dados e salvamos o resultado localmente. Fazemos isso não mais que 1 vez por hora. Durante a depuração, verificou-se que EXPLAIN trava no bloqueio da mesma maneira que a solicitação em si travaria, para a qual queremos conhecer o plano. Portanto, eu tive que adicionar setQueryTimeout (1).

E isso só funciona se a solicitação foi executada no mesmo banco de dados ao qual você se conectou (indicado ao configurar a conexão). E somente se você se conectou ao banco de dados sob o superusuário (postgres), do qual alguns podem ter medo. Portanto, você pode criar um usuário especial para monitoramento. Tudo, exceto a exibição dos planos, funcionará.

 CREATE USER pgmonuser WITH password 'pgmonuser'; GRANT pg_monitor TO pgmonuser; 

Faça o download no GitHub: https://github.com/dbacvetkov/PASH-Viewer/releases

UPD:
Na versão 0.3, adicionou suporte ao PostgreSQL 9.6 (existem apenas duas classes de espera - Lock e LWLock, tudo o resto funciona como "CPU") e PostgreSQL 9.4 - 9.5 (existe uma CPU ou um bloqueio aguardando em geral).
Na versão 0.3.1, adicionou o campo Tipo de back-end em Sessões principais e se livrou das barras brancas no gráfico.
Na versão 0.3.2, o trabalho aprimorado com planos incluiu algumas estatísticas sobre solicitações (Duração do AVG, Contagem de Chamadas) e a capacidade de visualizar dados históricos:
Como criar-pg_stat_activity-historical-table .

Obrigado e saudações:
Alexander Kardapolov para ASH-Viewer.
Anton Glushakov pela consulta e testes.
Dmitry Rudopysov por explicar como compilar e executar o projeto baixado do github.

Mais slides:


imagem

imagem

imagem

Source: https://habr.com/ru/post/pt413411/


All Articles