Obtener la última fecha de modificación de una tabla de base de datos PostgreSQL

35

Estoy tratando de obtener cuándo se modificó mi tabla al verificar la fecha de modificación del archivo como se describe en esta respuesta . Pero el resultado no siempre es correcto. La fecha de modificación del archivo se actualiza en varios minutos después de actualizar mi tabla. ¿Es correcto el comportamiento? ¿PostgreSQL almacena las modificaciones de la tabla en algún caché y luego lo vacía en el disco duro?

Entonces, ¿cómo obtengo la fecha correcta de la última modificación de una tabla (supongamos que las modificaciones de vacío automático también están bien)?

Yo uso PostgreSQL 9.2 en Linux Centos 6.2 x64.

madeja
fuente
44
No creo que el tiempo de modificación del archivo sea confiable. También podría cambiar debido al vacío automático. La única forma confiable es almacenar una marca de tiempo de modificación en su tabla, mantenida por un disparador.
a_horse_with_no_name
Una idea sería que la información almacenada en los archivos WAL se escriba en los archivos de datos un tiempo (más corto o más largo) después de confirmar la transacción. Si lo desea, puede llamar a esto un caché :) De lo contrario, secundo lo que dijo @a_horse_with_no_name.
dezso

Respuestas:

35

No existe un registro confiable y automático de la última hora modificada de una tabla. Usar el relfilenode está mal por muchas razones:

  • Las escrituras se registran inicialmente en el registro de encabezado de escritura (WAL), luego , lentamente, en el montón (los archivos de la tabla). Una vez que el registro está en WAL, Pg no se apresura a escribirlo en el montón, y es posible que ni siquiera se escriba hasta el próximo punto de control del sistema;

  • Las tablas más grandes tienen múltiples horquillas, tendría que verificar todas las horquillas y elegir la marca de tiempo más nueva;

  • Un simple SELECTpuede generar actividad de escritura en la tabla subyacente debido a la configuración de bits de pista;

  • autovaccum y otro mantenimiento que no cambia los datos visibles del usuario todavía modifica los archivos de relación;

  • Algunas operaciones, como vaccum full, reemplazarán el relfilenode. Es posible que no sea lo que espera si está tratando de verlo simultáneamente sin tomar un bloqueo adecuado.

Algunas opciones

Si no necesita confiabilidad, puede usar la información en pg_stat_databasey pg_stat_all_tables. Estos pueden darle el tiempo del último restablecimiento de estadísticas y las estadísticas de actividad desde el último restablecimiento de estadísticas. No te dice cuándo fue la actividad más reciente, solo que fue desde el último restablecimiento de estadísticas, y no hay información sobre lo que sucedió antes de que se restablecieran las estadísticas. Entonces es limitado, pero ya está ahí.

Una opción para hacerlo de manera confiable es usar un disparador para actualizar una tabla que contiene los últimos tiempos modificados para cada tabla. Tenga en cuenta que al hacerlo se serializarán todas las escrituras en la tabla , destruyendo la concurrencia. También agregará un poco de sobrecarga a cada transacción. No lo recomiendo

Una alternativa un poco menos horrible es usar LISTENy NOTIFY. Haga que un proceso de demonio externo se conecte a PostgreSQL y LISTENpara eventos. Use ON INSERT OR UPDATE OR DELETEdisparadores para enviar mensajes de NOTIFYcorreo electrónico cuando una tabla cambia, con la tabla oid como la carga útil de notificación. Estos se envían cuando se confirma la transacción. Su demonio puede acumular notificaciones de cambio y perezosamente escribirlas de nuevo en una tabla en la base de datos. Si el sistema falla, pierde su registro de las modificaciones más recientes, pero está bien, solo trata todas las tablas como recién modificadas si está iniciando después de un bloqueo.

Para evitar el peor de los problemas de concurrencia, puede registrar las marcas de tiempo de cambio utilizando un before insert or update or delete or truncate on tablename for each statement executedisparador, generalizado para tomar la relación oid como parámetro. Esto insertaría un (relation_oid, timestamp)par en una tabla de registro de cambios. Luego, tiene un proceso auxiliar en una conexión separada, o su aplicación lo llama periódicamente, agrega esa tabla para obtener la información más reciente, la fusiona en una tabla resumen de los cambios más recientes y trunca la tabla de registro. La única ventaja de esto sobre el enfoque de escuchar / notificar es que no pierde información sobre el bloqueo, pero también es menos eficiente.

Otro enfoque podría ser la de escribir una función de extensión de C que los usos (por ejemplo) ProcessUtility_hook, ExecutorRun_hook, etc a cambios en la tabla de trampas y las estadísticas de actualización pereza. No he mirado para ver cuán práctico sería esto; Eche un vistazo a las diversas opciones de _hook en las fuentes.

La mejor manera sería parchear el código de estadísticas para registrar esta información y enviar un parche a PostgreSQL para incluirlo en el núcleo. No solo comience escribiendo código; plantee su idea sobre los piratas informáticos una vez que lo haya pensado lo suficiente como para tener una forma bien definida de hacerlo (es decir, comience leyendo el código, no solo publique preguntando "¿cómo ...?"). Podría ser bueno agregar los últimos tiempos actualizados pg_stat_..., pero tendría que convencer a la comunidad de que valía la pena los gastos generales o proporcionar una forma de hacer un seguimiento opcional, y tendría que escribir el código para mantener las estadísticas y envíe un parche , porque solo alguien que quiera esta función se molestará con eso.

Como lo haría

Si tuviera que hacer esto y no tuviera tiempo de escribir un parche para hacerlo correctamente, probablemente usaría el enfoque de escuchar / notificar descrito anteriormente.

Actualización para las marcas de tiempo de confirmación de PostgreSQL 9.5

Actualización : PostgreSQL 9.5 tiene marcas de tiempo de confirmación . Si los ha habilitado postgresql.conf(y también lo hizo en el pasado), puede verificar la marca de tiempo de confirmación de la fila con el mayor xminpara aproximar la última hora modificada. Es solo una aproximación porque si se han eliminado las filas más recientes, no se contarán.

Además, los registros de marca de tiempo de confirmación solo se mantienen durante un tiempo limitado. Entonces, si desea saber cuándo se modifica una tabla que no se modifica mucho, la respuesta será efectivamente "no sé, hace un tiempo".

Craig Ringer
fuente
17

PostgreSQL 9.5 nos permite rastrear la última confirmación modificada.

  1. Verifique que la confirmación de seguimiento esté activada o desactivada utilizando la siguiente consulta

    show track_commit_timestamp;
  2. Si devuelve "ON", vaya al paso 3; de lo contrario, modifique postgresql.conf

    cd /etc/postgresql/9.5/main/
    vi postgresql.conf

    Cambio

    track_commit_timestamp = off

    a

    track_commit_timestamp = on

    Reiniciar el sistema

    Repita el paso 1.

  3. Use la siguiente consulta para rastrear la última confirmación

    SELECT pg_xact_commit_timestamp(xmin), * FROM  YOUR_TABLE_NAME;
    
    SELECT pg_xact_commit_timestamp(xmin), * FROM YOUR_TABLE_NAME where COLUMN_NAME=VALUE;
Thirumal
fuente
1
No tiene que reiniciar el sistema en el paso 2. simplemente reinicie el proceso. por ej sudo service postgresql restart.
ijoseph
3

Sí, esto puede esperarse: los datos sobre el cambio se almacenan en el registro de transacciones de inmediato. Los archivos de datos se pueden actualizar con checkpoint_timeout delay (el valor predeterminado es 5 minutos). Postgres no se mantiene de forma permanente en ningún momento que usted solicite.

Pavel Stehule
fuente
No estoy seguro de entender cómo responde esto a la pregunta. Sí, los datos se almacenan en el registro de transacciones, pero eso no significa que se pueda obtener una hora de modificación para una tabla específica fácilmente ( si ese contenido todavía está en el registro, se puede analizar el registro, pero las cosas se reproducen más bien con rapidez).
Charles Duffy
claro, puede obtener toda la información necesaria del registro, pero las preguntas se dirigieron a mtime of datafiles: la actualización de los archivos de datos puede ser bastante aleatoria, unos segundos, unos minutos (máximo 1 hora) después de la confirmación.
Pavel Stehule
El propio intento del OP fue mirar archivos, pero su intención real es claramente obtener una tabla en cualquier momento. Pero sí, entiendo de dónde vienes aquí (explicando por qué lo que estaban haciendo no funcionó) ahora.
Charles Duffy
2

Tengo casi el mismo requisito para mantener un caché de algunas tablas en una aplicación cliente. Digo casi , porque realmente no necesito saber la hora de la última modificación, sino solo para detectar si algo ha cambiado desde la última vez que se sincronizó el caché.

Aquí está mi enfoque:

Siempre que tenga una columna id(PK), created_on(marca de tiempo de inserción) y updated_on(actualizar marca de tiempo, puede ser NULL) en cada tabla, puede

SELECT id,greatest(created_on,updated_on) FROM %s ORDER BY greatest(created_on,updated_on) DESC LIMIT 1;

Si concatena esto y antepone el número de filas, puede crear una etiqueta de versión que se vea count:id#timestamp, y será única para cada versión de los datos en la tabla.

Laurent
fuente