Pregunta

Considere los dos siguientes ejemplos de código de Python, lo que logra lo mismo pero con una diferencia de rendimiento significativa y sorprendente.

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

Y:

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

La declaración Crear para la prueba de la tabla es:

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

Y esa tabla contiene 100000 filas y prueba de análisis de vacío; ha sido ejecutado.

Obtuve los siguientes resultados constantemente en varios intentos.

Primer ejemplo de código:

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

Segundo ejemplo de código:

Finished: update starting commit: 24.574401185
Finished committing: 24.7331461431

Esto es muy sorprendente para mí, ya que creo que debería ser exactamente opuesto, lo que significa que una actualización que usa el cursor debería ser significativamente más rápido según este responder.

¿Fue útil?

Solución

No creo que la prueba esté equilibrada: su primer código está obteniendo los datos del cursor, luego actualizando, mientras que el segundo se actualiza ciegamente por ID sin obtener los datos. Supongo que la primera secuencia de código se traduce en un comando Fetch seguido de la actualización, por lo que son dos cambios de comando cliente/servidor en lugar de uno.

(También el primer código comienza bloqueando cada fila en la tabla: esto lleva toda la tabla a la memoria caché del búfer; aunque pienso en ello, dudo que esto realmente impacte el rendimiento, pero no lo mencionó)

También tbh creo que para una tabla simple, no habrá muy diferente entre la actualización de CTID (que supongo que es cómo where current of... funciona) y actualización a través de una clave principal: la actualización de PKey es una búsqueda de índice adicional, pero a menos que el índice sea enorme No es una gran degradación.

Para actualizar 100,000 filas como esta, sospecho que la mayor parte del tiempo se lleva a generar las tuplas adicionales e insertarlas o agregarlas a la mesa, en lugar de localizar la tupla anterior para marcarlo como eliminado.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top