
Esta herramienta fue escrita por interés deportivo cuando descubrí que la vista pg_stat_activity en PostgreSQL 10 tiene los campos wait_event_type y wait_event, que son muy similares en esencia a wait_class y el evento de v $ session.
Trabajando activamente con el
programa ASH-Viewer de
akardapolov en este momento, tenía curiosidad por lo difícil que es reescribir este producto en Postgres. Dado que no soy un desarrollador profesional, no fue fácil, pero sí muy interesante. En el proceso, incluso encontré, me parece, un par de errores importantes que aparecen en el programa original para Oracle, así como en la Edición Estándar.
Los principios de PASH-Viewer:
No se necesitan extensiones. Tomamos datos exclusivamente de la vista integrada pg_stat_activity.
Una vez por segundo, se realiza una solicitud para sesiones activas:
pg_stat_activity texto de solicitudSELECT 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();
Una vez cada 15 segundos, los datos de las últimas 15 imágenes se promedian y se muestran en un gráfico.
El ID de SQL que necesito para agrupar las consultas en la sección Top SQL, lo genero yo mismo, no tiene nada que ver con el queryid de pg_stat_statements. Estaba pensando cómo usar queryid, pero desafortunadamente no encontré una manera de hacer coincidir las consultas de estas dos vistas. Sería genial si los desarrolladores agregaran el campo queryid a pg_stat_activity.
Id. De SQL = primeros 13 caracteres de md5 (texto de consulta normalizado).
Un texto de consulta normalizado es una consulta en la que se eliminan caracteres de nueva línea y espacios adicionales, y los literales se reemplazan con $ 1, $ 2, etc. ... Fue difícil para mí escribir una buena función de normalización de consulta. Escribí uno malo. Cito el texto, pero por favor no lo mire, de lo contrario me da vergüenza. Mejor manda uno bueno.
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(); }
Fue difícil completar el plan de ejecución de la consulta. Es a Oracle a quien vienes y dices: "Dame un plan para sqlid = ...", y él te responde: "¿Tienes el último, o ayer, o muestras todo para el último mes con estadísticas de ejecución para cada uno?" Y PostgreSQL te responde: "¿Qué es sqlid?".
Por lo tanto, para consultas como SELECT / UPDATE / INSERT / DELETE, enviamos el comando EXPLAIN a la base de datos y guardamos el resultado localmente. Hacemos esto no más de 1 vez por hora. Durante la depuración, se descubrió que EXPLAIN se bloquea en la cerradura de la misma manera que la solicitud en sí misma, para lo cual queremos conocer el plan. Por lo tanto, tuve que agregar setQueryTimeout (1).
Y esto solo funciona si la solicitud se ejecutó en la misma base de datos a la que se conectó (indicado al configurar la conexión). Y solo si se conectó a la base de datos bajo el superusuario (postgres), a lo que algunos pueden temer. Por lo tanto, puede crear un usuario especial para el monitoreo. Todo, excepto la presentación de planos, funcionará.
CREATE USER pgmonuser WITH password 'pgmonuser'; GRANT pg_monitor TO pgmonuser;
Descargar desde GitHub:
https://github.com/dbacvetkov/PASH-Viewer/releasesUPD:En la versión 0.3, agregó soporte para PostgreSQL 9.6 (solo hay dos clases de espera: Lock y LWLock, todo lo demás funciona como "CPU") y PostgreSQL 9.4 - 9.5 (hay una CPU o Lock esperando en general).
En la versión 0.3.1, agregó el campo Tipo de backend en las Sesiones principales y eliminó las barras blancas en el gráfico.
En la versión 0.3.2, se mejoró el trabajo con los planes, se agregaron algunas estadísticas sobre las solicitudes (Duración AVG, Conteo de llamadas) y la capacidad de ver datos históricos:
Cómo-crear-pg_stat_activity-historical-table .
Gracias y saludos:
Alexander Kardapolov para ASH-Viewer.
Anton Glushakov para consultas y pruebas.
Dmitry Rudopysov por explicar cómo compilar y ejecutar el proyecto descargado de github.
Más diapositivas:


