Question

Considérons les deux exemples suivants de code Python, ce qui permet d'obtenir la même chose, mais avec une différence de performance significative et surprenante.

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()

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()

L'instruction CREATE pour le test de la table est:

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

Ce tableau contient 100000 lignes et VACUUM ANALYZE ESSAI; a été exécuté.

Je suis arrivé les résultats suivants régulièrement sur plusieurs tentatives.

Premier exemple de code:

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

Deuxième exemple de code:

Finished: update starting commit: 24.574401185
Finished committing: 24.7331461431

Ceci est très surprenant pour moi que je pense est devrait être exactement le contraire, ce qui signifie qu'une mise à jour en utilisant le curseur devrait être nettement plus rapide selon cette réponse .

Était-ce utile?

La solution

Je ne pense pas que le test est balanced- votre premier code les données du aller chercher le curseur, puis la mise à jour, tandis que la seconde est mise à jour aveuglément par ID sans aller chercher les données. Je suppose que la première séquence de code se traduit par une commande FETCH suivie MISE À JOUR de sorte que, par opposition à une commande client est deux retournements / serveur.

(mais aussi les premiers départs de code de verrouillage chaque ligne de la table- ce tractions la table entière dans le cache- tampon bien y penser, je doute ce fait affecte les performances, mais vous ne l'avez pas fait mention)

Je pense aussi TBH que pour une table simple, il n'y aura pas très différent entre la mise à jour par ctid (que je suppose est de savoir comment fonctionne where current of...) et la mise à jour par un Key- primaire la mise à jour de pkey est une recherche d'index supplémentaire, mais à moins que l'indice est énorme il n'y a pas beaucoup d'une dégradation.

Pour la mise à jour de 100.000 lignes comme ça, je soupçonne que la plupart du temps est repris générer les tuples supplémentaires et de les insérer dans ou en les ajoutant à la table, plutôt que de localiser le tuple précédent pour le marquer comme supprimé.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top