Si tengo una UPDATE
declaración que en realidad no cambia ningún dato (porque los datos ya están en el estado actualizado). ¿Hay algún beneficio de rendimiento al marcar la WHERE
cláusula para evitar la actualización?
Por ejemplo, habría alguna diferencia en la velocidad de ejecución entre ACTUALIZACIÓN 1 y ACTUALIZACIÓN 2 en lo siguiente:
CREATE TABLE MyTable (ID int PRIMARY KEY, Value int);
INSERT INTO MyTable (ID, Value)
VALUES
(1, 1),
(2, 2),
(3, 3);
-- UPDATE 1
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2
AND Value <> 2;
SELECT @@ROWCOUNT;
-- UPDATE 2
UPDATE MyTable
SET
Value = 2
WHERE
ID = 2;
SELECT @@ROWCOUNT;
DROP TABLE MyTable;
La razón por la que pregunto es que necesito el recuento de filas para incluir la fila sin cambios, así sé si hacer una inserción si la ID no existe. Como tal, utilicé el formulario ACTUALIZAR 2. Si hay un beneficio de rendimiento al usar el formulario ACTUALIZAR 1, ¿es posible obtener el recuento de filas que necesito de alguna manera?
sql-server
query-performance
update
Martin Brown
fuente
fuente
Respuestas:
Ciertamente, podría haber una ligera diferencia de rendimiento debido a la ACTUALIZACIÓN 1 :
Sin embargo, la diferencia que hay que medir en su sistema con su esquema, datos y carga del sistema. Hay varios factores que influyen en el impacto que tiene una ACTUALIZACIÓN que no se actualiza:
UPDATE TableName SET Field1 = Field1
, se activará un desencadenador de actualización e indicará que el campo se actualizó (si marca usando las funciones UPDATE () o COLUMNS_UPDATED ), y que el campo en ambas tablasINSERTED
y en lasDELETED
tablas tiene el mismo valor.Además, la siguiente sección de resumen se encuentra en el artículo de Paul White, El impacto de las actualizaciones no actualizadas (como lo señaló @spaghettidba en un comentario sobre su respuesta):
Tenga en cuenta (especialmente si no sigue el enlace para ver el artículo completo de Paul), los siguientes dos elementos:
Las actualizaciones que no se actualizan todavía tienen alguna actividad de registro, lo que muestra que una transacción está comenzando y terminando. Es solo que no ocurre ninguna modificación de datos (lo que sigue siendo un buen ahorro).
Como dije anteriormente, debe probar en su sistema. Use las mismas consultas de investigación que Paul está usando y vea si obtiene los mismos resultados. Estoy viendo resultados ligeramente diferentes en mi sistema de lo que se muestra en el artículo. Todavía no hay páginas sucias para escribir, pero un poco más de actividad de registro.
Simplísticamente, si solo está tratando con una sola fila, puede hacer lo siguiente:
Para varias filas, puede obtener la información necesaria para tomar esa decisión utilizando la
OUTPUT
cláusula Al capturar exactamente qué filas se actualizaron, puede reducir los elementos para buscar y conocer la diferencia entre no actualizar filas que no existen en lugar de no actualizar filas que existen pero que no necesitan la actualización.Muestro la implementación básica en la siguiente respuesta:
¿Cómo evitar el uso de la consulta de combinación al insertar múltiples datos usando el parámetro xml?
El método que se muestra en esa respuesta no filtra las filas que existen, pero no es necesario actualizarlas. Esa parte podría agregarse, pero primero debería mostrar exactamente dónde está obteniendo su conjunto de datos en el que se está fusionando
MyTable
. ¿Vienen de una mesa temporal? ¿Un parámetro con valores de tabla (TVP)?ACTUALIZACIÓN 1:
Finalmente pude hacer algunas pruebas y esto es lo que encontré con respecto al registro de transacciones y el bloqueo. Primero, el esquema de la tabla:
A continuación, la prueba actualiza el campo al valor que ya tiene:
Resultados:
Finalmente, la prueba que filtra la actualización debido a que el valor no cambia:
Resultados:
Como puede ver, no se escribe nada en el Registro de transacciones al filtrar la fila, a diferencia de las dos entradas que marcan el comienzo y el final de la Transacción. Y si bien es cierto que esas dos entradas son casi nada, siguen siendo algo.
Además, el bloqueo de los recursos PAGE y KEY es menos restrictivo cuando se filtran las filas que no han cambiado. Si ningún otro proceso está interactuando con esta tabla, entonces es probable que no sea un problema (pero ¿qué tan probable es eso realmente?). Tenga en cuenta que las pruebas que se muestran en cualquiera de los blogs vinculados (e incluso mis pruebas) suponen implícitamente que no hay contención en la tabla ya que nunca forma parte de las pruebas. Al decir que las actualizaciones que no se actualizan son tan livianas que no vale la pena realizar el filtrado, deben tomarse con un grano de sal ya que las pruebas se han realizado, más o menos, en el vacío. Pero en Producción, esta tabla probablemente no esté aislada. Por supuesto, bien podría ser que el poco registro y los bloqueos más restrictivos no se traduzcan en menos eficiencia. Entonces, ¿la fuente de información más confiable para responder esta pregunta? Servidor SQL. Específicamente:su servidor SQL Le mostrará qué método es mejor para su sistema :-).
ACTUALIZACIÓN 2:
Si las operaciones en las que el nuevo valor es el mismo que el valor actual (es decir, sin actualización), enumere las operaciones en las que el nuevo valor es diferente y la actualización es necesaria, entonces el siguiente patrón podría ser aún mejor, especialmente si Hay mucha discusión sobre la mesa. La idea es hacer un simple
SELECT
primero para obtener el valor actual. Si no obtiene un valor, entonces tiene su respuesta con respecto alINSERT
. Si tiene un valor, puede hacer un simpleIF
y emitir elUPDATE
único si es necesario.Resultados:
Por lo tanto, solo hay 2 bloqueos adquiridos en lugar de 3, y ambos bloqueos son Intent Shared, no Intent eXclusive o Intent Update ( Compatibilidad de bloqueo ). Teniendo en cuenta que cada bloqueo adquirido también se liberará, cada bloqueo es realmente 2 operaciones, por lo que este nuevo método es un total de 4 operaciones en lugar de las 6 operaciones en el método propuesto originalmente. Teniendo en cuenta que esta operación se ejecuta una vez cada 15 ms (aproximadamente, como lo indica el OP), eso es aproximadamente 66 veces por segundo. Entonces, la propuesta original asciende a 396 operaciones de bloqueo / desbloqueo por segundo, mientras que este nuevo método equivale a solo 264 operaciones de bloqueo / desbloqueo por segundo de bloqueos aún más livianos. Esto no es garantía de un rendimiento increíble, pero ciertamente vale la pena probarlo :-).
fuente
Aleja un poco y piensa en la imagen más grande. En el mundo real, su declaración de actualización realmente se verá así:
¿O se verá más así?
Porque en el mundo real, las tablas tienen muchas columnas. Eso significa que tendrá que generar una gran cantidad de lógica de aplicación dinámica compleja para crear cadenas dinámicas, O tendrá que especificar cada contenido de campo antes y después, cada vez.
Si construye estas declaraciones de actualización dinámicamente para cada tabla, solo pasando los campos que se están actualizando, puede encontrarse rápidamente con un problema de contaminación de caché del plan similar al problema de tamaños de parámetros de NHibernate desde hace unos años. Peor aún, si construye las declaraciones de actualización en SQL Server (como en los procedimientos almacenados), entonces quemará preciosos ciclos de CPU porque SQL Server no es terriblemente eficiente para concatenar cadenas juntas a escala.
Debido a esas complejidades, generalmente no tiene sentido hacer este tipo de comparación fila por fila, campo por campo, mientras realiza las actualizaciones. Piense en operaciones basadas en conjuntos en su lugar.
fuente
Podría ver una ganancia de rendimiento al omitir filas que no necesitan actualizarse solo cuando el número de filas es grande (menos registro, menos páginas sucias para escribir en el disco).
Cuando se trata de actualizaciones de una sola fila como en su caso, la diferencia de rendimiento es completamente insignificante. Si actualizar las filas en todos los casos lo hace más fácil para usted, hágalo.
Para obtener más información sobre el tema, consulte Actualizaciones sin actualización de Paul White
fuente
Puede combinar la actualización e insertarla en una sola declaración. En SQL Server, puede usar una instrucción MERGE para realizar la actualización y la inserción si no se encuentra. Para MySQL, puede usar INSERTAR EN LA ACTUALIZACIÓN CLAVE DUPLICADA .
fuente
En lugar de verificar los valores de todos los campos, ¿no puede obtener un valor hash utilizando las columnas que le interesan y luego compararlo con el hash almacenado en la fila de la tabla?
fuente