Tengo una pregunta relacionada con el rendimiento. Digamos que tengo un usuario con nombre Michael. Tome la siguiente consulta:
UPDATE users
SET first_name = 'Michael'
WHERE users.id = 123
¿Realmente la consulta ejecutará la actualización, aunque se actualice al mismo valor? Si es así, ¿cómo evito que suceda?
postgresql
performance
update
postgresql-performance
OneSneakyMofo
fuente
fuente
Respuestas:
Debido al modelo MVCC de Postgres, y de acuerdo con las reglas de SQL, un
UPDATE
escribe una nueva versión de fila para cada fila que no está excluida en laWHERE
cláusula.Esto lo hace tiene un impacto más o menos sustancial en el rendimiento, directa e indirectamente. Las "actualizaciones vacías" tienen el mismo costo por fila que cualquier otra actualización. Disparan desencadenantes (si están presentes) como cualquier otra actualización, tienen que estar registrados en WAL y producen filas muertas que hinchan la tabla y causan más trabajo para
VACUUM
más adelante como cualquier otra actualización.Las entradas de índices y las columnas TOASTed en las que no se cambia ninguna de las columnas involucradas pueden permanecer iguales, pero eso es cierto para cualquier fila actualizada. Relacionado:
Casi siempre es una buena idea excluir esas actualizaciones vacías (cuando existe una posibilidad real de que ocurra). No proporcionó una definición de tabla en su pregunta (que siempre es una buena idea). Tenemos que suponer que
first_name
puede ser NULL (lo que no sería sorprendente para un "nombre"), por lo tanto, la consulta debe usar una comparación NULL-safe :Si
first_name IS NULL
antes de la actualización, una prueba con solofirst_name <> 'Michael'
evaluaría a NULL y, como tal, excluiría la fila de la actualización. Error furtivo Sin embargo, si la columna está definidaNOT NULL
, use la simple verificación de igualdad, porque es un poco más barato.Relacionado:
fuente
Indexes entries and TOASTed columns where none of the involved columns are changed can stay the same
¿Pero no tendrían que actualizarse para señalar la nueva ubicación de la fila?rollback
manejo de instantáneas, administración de bloqueos, WAL, y qué no ...Los ORM como Ruby on Rail ofrecen una ejecución diferida que marca un registro como modificado (o no) y luego, cuando es necesario o llamado, luego envía el cambio a la base de datos.
PostgreSQL es una base de datos y no un ORM. Hubiera disminuido el rendimiento si se tomara el tiempo de verificar si un nuevo valor era el mismo que el valor actualizado en su consulta.
Por lo tanto, actualizará el valor independientemente de si es el mismo que el nuevo valor o no.
Si desea evitar esto, puede usar un código como lo sugirió Max Vernon en su respuesta.
fuente
Simplemente podría agregar a la
where
cláusula:Si
first_name
se define comoNOT NULL
, laOR first_name IS NULL
parte se puede quitar.La condición:
También se puede escribir con más elegancia como (en la respuesta de Erwin):
fuente
NULL
@erwinDesde el punto de vista de la base de datos
La respuesta a tu pregunta es sí. La actualización tendrá lugar. La base de datos no verifica el valor anterior, solo establece el nuevo valor.
Como esto sucede en la memoria (y solo se escribirá en los archivos de datos después de emitir una confirmación), el rendimiento no sería un problema.
Desde una perspectiva ORM
Normalmente tendrá un Objeto que representa una sola fila de la base de datos (puede ser mucho más complejo que eso, pero hagámoslo simple). Este objeto se gestiona en la memoria (en el nivel del servidor de aplicaciones) y solo la última versión confirmada de ese objeto realmente llegará a la base de datos en un momento determinado.
Eso puede explicar el comportamiento diferente.
Ahora, no comparemos un buque de carga con una impresora 3D. El hecho de que pueda enviar impresoras 3D utilizando buques de carga no significa que pueda haber algún tipo de comparación entre ellos.
¡Disfrutar!
Espero que esto haya aclarado algunos conceptos.
fuente