2016-05-10 4 views
1

Wir haben eine PL/pgSQL-Funktion geschrieben, um Zeitstempel in einer Audit-Tabelle aufzuzeichnen. PostgreSQL-Anweisung Caching jedoch nicht now() auf jedem Aufruf neu berechnen, was zu veralteten (dh alten) Zeitstempeln in unserer Audit-Tabelle aufgezeichnet werden.PostgreSQL-Statement-Caching, das die erwarteten Ergebnisse stört

Wir betreiben Postgres 9.2. Laut der Dokumentation http://www.postgresql.org/docs/9.2/static/plpgsql-implementation.html#PLPGSQL-PLAN-CACHING (zum Ende ihres Artikels scrollen), ist die Empfehlung auf Aufrufe an now() angewiesen.

Diese Funktion funktioniert nicht wie erwartet:

CREATE OR REPLACE FUNCTION save(txd integer) RETURNS void AS $$ 
BEGIN 
    INSERT INTO audit (id, mtime) VALUES (txd,now()); 
END;$$ 

Mit einer Tabelle wie folgt definiert:

CREATE TABLE audit (
    id integer NOT NULL, 
    mtime timestamp without time zone NOT NULL, 
    CONSTRAINT audit_pkey PRIMARY KEY (id) 
) 

Ein einfacher Python 2.7 Skript psycopg2 verwendet, kann verwendet werden, um das Problem zu demonstrieren:

import datetime, psycopg2, time 
def tm(): 
    # connect and clear contents 
    con = psycopg2.connect('dbname=postgres user=postgres') 
    cur = con.cursor() 
    cur.execute('TRUNCATE audit') 

    # Add a record, wait a second, add another 
    cur.execute('SELECT save(1)') 
    time.sleep(1.0) 
    cur.execute('SELECT save(2)') 

    # List the contents 
    cur.execute('SELECT * FROM audit') 
    for row in cur.fetchall(): 
     print("modified %s" % row[1]) 
    cur.close() 
    con.close() 

Wenn Sie dieses Skript ausführen, werden Sie feststellen, dass die beiden Instanzen o f modifizierten Zeiten werden den exakt gleichen Wert melden, auch wenn wir

>>> tm() 
modified 2016-05-10 11:05:21.766005 
modified 2016-05-10 11:05:21.766005 

Hinweis einen kleinen 1-Sekunden-Schlaf zwischen INSERTs eingefügt: Wir haben sogar das Beispiel versuchen, von Postgres in den verknüpften Artikeln zur Verfügung gestellt. Es gibt keinen Unterschied in der Ausgabe anhand ihres Beispiels:

CREATE OR REPLACE FUNCTION save(txd integer) RETURNS void AS $$ 
DECLARE 
    curtime timestamp; 
BEGIN 
    curtime = 'now'; 
    INSERT INTO audit (id, mtime) VALUES (txd,curtime); 
END;$$ 

Könnte uns jemand direkt darauf hinweisen, wo wir hier falsch liegen?

+1

'now()' den Zeitstempel zurück ** bei Transaktion beginnen **. Wenn Sie die tatsächliche Zeit auf Untertransaktionsebene möchten, benötigen Sie 'clock_timestamp()' http://www.postgresql.org/docs/9.5/static/functions-datetime.html – joop

+0

Vielen Dank! Wenn Sie dies zur Antwort machen, werde ich vergeben. – user590028

Antwort

Verwandte Themen