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?
'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
Vielen Dank! Wenn Sie dies zur Antwort machen, werde ich vergeben. – user590028