Frage

Betrachten Sie die beiden folgenden Beispiele für Python -Code, die das gleiche, aber mit einem signifikanten und überraschenden Leistungsunterschied erreichen.

import psycopg2, time

conn = psycopg2.connect("dbname=mydatabase user=postgres")
cur = conn.cursor('cursor_unique_name')  
cur2 = conn.cursor()

startTime = time.clock()
cur.execute("SELECT * FROM test for update;")
print ("Finished: SELECT * FROM test for update;: " + str(time.clock() - startTime));
for i in range (100000):
    cur.fetchone()
    cur2.execute("update test set num = num + 1 where current of cursor_unique_name;")
print ("Finished: update starting commit: " + str(time.clock() - startTime));
conn.commit()
print ("Finished: update : " + str(time.clock() - startTime));

cur2.close()
conn.close()

Und:

import psycopg2, time

conn = psycopg2.connect("dbname=mydatabase user=postgres")
cur = conn.cursor('cursor_unique_name')  
cur2 = conn.cursor()

startTime = time.clock()
for i in range (100000):
    cur2.execute("update test set num = num + 1 where id = " + str(i) + ";")
print ("Finished: update starting commit: " + str(time.clock() - startTime));
conn.commit()
print ("Finished: update : " + str(time.clock() - startTime));

cur2.close()
conn.close()

Die Anweisung erstellen für den Tabellentest lautet:

CREATE TABLE test (id serial PRIMARY KEY, num integer, data varchar);

Und diese Tabelle enthält 100000 Zeilen und Vakuumanalyse -Test; wurde geführt.

Ich habe die folgenden Ergebnisse bei mehreren Versuchen konsequent erhalten.

Erster Codebeispiel:

Finished: SELECT * FROM test for update;: 0.00609304950429
Finished: update starting commit: 37.3272754429
Finished: update : 37.4449708474

Beispiel für zweite Code:

Finished: update starting commit: 24.574401185
Finished committing: 24.7331461431

Dies ist für mich sehr überraschend, wie ich denken würde, dass es genau entgegengesetzt sein sollte, was bedeutet, dass ein Update mit Cursor lautet. Dies Antworten.

War es hilfreich?

Lösung

Ich glaube nicht, dass der Test ausgeglichen ist. Ihr erster Code holt die Daten vom Cursor ab und aktualisiert, während das zweite blind den Aktualisieren durch ID aktualisiert, ohne die Daten abzurufen. Ich gehe davon aus, dass die erste Codesequenz in einen Fetch-Befehl übersetzt wird, gefolgt von Aktualisierungen. Dies sind also zwei Client/Server-Befehlswendungen im Gegensatz zu einem.

(Auch der erste Code beginnt damit, jede Zeile in der Tabelle zu sperren. Dies zieht die gesamte Tabelle in den Puffer-Cache- obwohl ich darüber nachdenke, bezweifle ich, dass dies tatsächlich die Leistung beeinflusst, aber Sie haben ihn nicht erwähnt.)

Ich denke auch, dass es für eine einfache Tabelle nicht viel unterschiedlich zwischen dem Aktualisieren von CTID gibt (was ich annehme, wie es ist, wie wie where current of... funktioniert) und aktualisiert über eine Primärschlüssel. Das PKEy-Update ist eine zusätzliche Index-Suche, aber es sei denn, der Index ist riesig Es ist kein großer Abbau.

Für die Aktualisierung von 100.000 Zeilen wie diese vermute ich, dass die meiste Zeit die Erzeugung der zusätzlichen Tupel und das Einfügen in sie in den Tisch generiert wird, anstatt das vorherige Tupel zu lokalisieren, um es als gelöscht zu markieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top