¿Cómo puedo saber qué tan avanzado está mi consulta PostgreSQL?

35

Tengo una idea bastante decente de cuántas filas procesará realmente mi consulta SELECT ... INTO (por ejemplo, sé cuántas se materializarán).

Entiendo que Postgres no me dirá el porcentaje de completitud, ¿hay alguna manera (enterrada en registros, tablas del sistema o de otra manera) que pueda averiguar cuántas filas se han bombeado en la tabla de destino o que han sido leídas por la consulta SELECT ?

Mark Elliot
fuente

Respuestas:

33

Como Daniel Vérité mencionó, no parece haber una solución genérica. Al cargar datos en una tabla desde un archivo, se puede usar la siguiente técnica para obtener el progreso de la carga.

COPY barra de progreso de la consola de comandos

Crea una mesa vacía.

CREATE TABLE mytest (n int);

Cree un archivo de datos con 10 millones de líneas para cargar en la tabla.

$ seq 10000000 > /tmp/data.txt

Cargue datos del archivo en la tabla y muestre una barra de progreso.

$ pv /tmp/data.txt | psql -c "COPY mytest FROM STDIN;"

Manifestación

ingrese la descripción de la imagen aquí

Como funciona esto

Mediante el uso de la opción STDIN de comandos de copia, podemos alimentar los datos para la operación de copia desde otro proceso. El comando pv generará un archivo y hará un seguimiento de su progreso mostrando una barra de progreso, ETA, el tiempo total transcurrido y la velocidad de transferencia de datos.

Barra de progreso gráfica del comando COPY

Usando la misma técnica general, podríamos mostrar una barra de progreso en una aplicación gráfica o una aplicación basada en la web. Usando python, por ejemplo, el módulo psycopg2 le permite llamar al comando copiar con un objeto de archivo de su elección. Luego puede realizar un seguimiento de la cantidad de su objeto de archivo que se ha leído y mostrar una barra de progreso.

Marwan Alsabbagh
fuente
2
No había encontrado el pvcomando antes, y no estaba instalado en mi servidor Debian por defecto, pero está en el repositorio. La descripción dice que "pv (Pipe Viewer) se puede insertar en cualquier canalización normal entre dos procesos para dar una indicación visual de qué tan rápido pasan los datos". Un comando muy útil!
Richard Turner
27

No parece haber un método genérico compatible, pero hay algunos trucos que se pueden usar en contextos limitados para evaluar el progreso de una consulta individual. Éstos son algunos de ellos.

Secuencias

Cuando una consulta SELECT o UPDATE incluye alguna nextval(sequence_name), o un INSERT tiene una columna de destino con un nextvalvalor predeterminado, el valor de secuencia actual se puede consultar repetidamente en otra sesión conSELECT sequence_name.last_value . Funciona porque las secuencias no están delimitadas por transacciones. Cuando el plan de ejecución es tal que la secuencia se incrementa linealmente durante la consulta, puede usarse como un indicador de progreso.

pgstattuple

El módulo contrib pgstattuple proporciona funciones que pueden ver directamente las páginas de datos. Parece que cuando las tuplas se insertan en una tabla vacía y aún no se confirman, se cuentan en el dead_tuple_countcampo desde la pgstattuplefunción.

Demostración con 9.1: crea una tabla vacía

CREATE TABLE tt AS (n numeric);

Insertemos 10M filas en él:

INSERT INTO tt SELECT * FROM random() from generate_series(1,10000000);

En otra sesión, verifique pgstattuple cada segundo durante la inserción:

$ while true;
   do psql -Atc "select dead_tuple_count from pgstattuple('tt')";
   sleep 1;
  done

Resultados:

0 0
69005
520035
1013430
1492210
1990415
2224625
2772040
3314460
3928660
4317345
4743770
5379430
6080950
6522915
7190395
7953705
8747725
9242045
0 0

Vuelve a 0 cuando finaliza la inserción (todas las tuplas se vuelven visibles y vivas).

Este truco también se puede usar cuando la tabla no se ha creado recientemente, pero dead_tuple_countes probable que la inicial tenga un valor distinto de cero y también puede cambiar simultáneamente si está ocurriendo otra actividad de escritura como el vacío automático (¿presumiblemente? ¿No está seguro de qué nivel de concurrencia a esperar con autovacuum).

Sin embargo, no se puede usar si la tabla es creada por la declaración misma ( CREATE TABLE ... AS SELECTo SELECT * INTO newtable), ya que la creación se transa. La solución alternativa sería crear la tabla sin filas (agregar LIMIT 0) y completarla en la próxima transacción.

Tenga en cuenta que pgstattupleno es gratis: escanea toda la tabla en cada llamada. También se limita a los superusuarios.

Contador personalizado

En el blog de Pavel Stehule, proporciona una función de contador implementada en C que genera AVISOS en un número específico de ejecuciones. Debe combinar la función con la consulta de alguna manera para permitir que el ejecutor la llame. Los avisos se envían durante la consulta y no necesitan una sesión separada, solo un cliente SQL que los muestre ( psqlsiendo el candidato obvio).

Ejemplo de INSERT INTO reelaborado para generar avisos:

/* transformation */
INSERT INTO destination_table
   SELECT (r).*
  FROM (SELECT counter(to_destination_table(_source), 1000, true) r
           FROM source _source) x

Pregunta relacionada sobre stackoverflow, para funciones:
cómo informar el progreso de la función PostgreSQL de larga duración al cliente

Opciones de futuro?

A partir de mayo de 2017, hay un parche prometedor enviado a la comunidad de desarrolladores: [PATCH v2] Comando de progreso para monitorear la progresión de consultas SQL de larga ejecución

que podría terminar como una solución genérica en PostgreSQL 11 o posterior. Los usuarios que desean participar en las funciones de trabajo en progreso pueden aplicar la última versión del parche y probar el PROGRESScomando propuesto .

Daniel Vérité
fuente
3

Hasta que la funcionalidad del informe de progreso no se extienda, como @AmirAliAkbari mencionó en su respuesta, aquí hay una solución alternativa a nivel de sistema operativo.

Esto funciona solo en Linux, pero probablemente haya soluciones similares fácilmente buscables para cualquier sistema operativo.

La ventaja más grande y también la desventaja de PostgreSQL, que todos sus backends son procesos simples de un solo subproceso, utilizando lseek(), read()y write()para manipular sus archivos de la tabla, mientras que están interactuando en el MEM y los bloqueos compartidos.

Esto da como resultado que todos sus procesos de back-end estén trabajando siempre en una sola consulta, que se puede encontrar fácilmente, y fácilmente straced.

Primero, puede ver el PID de fondo desde SELECT * FROM pg_stat_activity;:

29805270 | dbname  | 20019 |    16384 | username  |                  |             |                 |          -1 | 2018-09-19 21:31:57.68234+02  | 2018-09-19 21:31:59.435376+02 | 2018-09-\
20 00:34:30.892382+02 | 2018-09-20 00:34:30.892386+02 | Client          | ClientRead | active              |       92778 |        92778 |  INSERT INTO ...something...

La tercera columna es el pid. En PostgreSQL, es lo mismo que el proceso de Linux pid del backend.

A continuación, puede dividirlo, por ejemplo, mediante un strace -p 20019 -s 8192: ( -s 8192es útil porque postgresql funciona con bloques largos de 8192 bytes).

sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
recvfrom(10, "Q\0\0\1\267 INSERT <removed by @peterh>", 8192, 0, NULL, NULL) = 440
sendto(10, "C\0\0\0\17INSERT 0 1\0Z\0\0\0\5T", 22, 0, NULL, 0) = 22
lseek(298, 343634345)...
read(298, "<block data which was read in>"....
write(298, "<block data which was written out>"...

Los significados:

  • sendtoOcurre si el servidor responde algo a un cliente. En el ejemplo, responde el resultado de una INSERTconsulta.
  • recvfromsucede si el servidor obtiene algo de un cliente. Normalmente es una consulta nueva, en el ejemplo, otra más INSERT.
  • lseek sucede si el backend cambia de posición en un archivo de tabla.
  • read sucede si el backend lee un bloque desde un archivo de tabla.
  • write sucede si el backend escribe un bloque en un archivo de tabla.

En el caso de ready write, también puede ver el contenido de ese bloque en la tabla. Puede ayudar mucho entender, qué está haciendo y dónde está.

En el caso de recvfrom, puede ver la consulta real que tiene el backend.

Peter dice reinstalar a Mónica
fuente
2

Como se dijo en otras respuestas, actualmente no existe una forma directa de informar el progreso en general.

PostgreSQL tiene la capacidad de informar el progreso de ciertos comandos durante la ejecución del comando. Actualmente, el único comando que admite informes de progreso es VACUUM. Esto puede ampliarse en el futuro.

Sin embargo, a partir de 9.6, cada vez que VACUUMse ejecute, la pg_stat_progress_vacuumvista contendrá una fila para cada backend (incluidos los procesos de trabajo de vacío automático) que se está aspirando actualmente. Se pg_stat_progress_vacuumpueden encontrar más detalles sobre la documentación: 27.4 Informes de progreso .

Amir Ali Akbari
fuente