Su compañero MVP, Jamie Thomson, señaló recientemente que hay un error de "resultados incorrectos" en SQL Server que puede manifestarse cuando se cumplen las siguientes condiciones:
- Tiene una vista indexada que une al menos dos tablas;
- esas tablas están restringidas en cualquier dirección por una clave externa de una sola columna;
- realiza actualizaciones a la(s) tabla(s) base usando
MERGE
que incluye tantoUPDATE
y (DELETE
oINSERT
) acciones; y, - posteriormente emite consultas que hacen referencia al índice en la vista (intencionalmente o no).
Lamentablemente, el artículo de la base de conocimientos que describe el problema (KB n.° 2756471) es bastante escaso en detalles. No te dicen cómo reproducir el problema, ni siquiera qué, específicamente, debes estar buscando para ver si esto te afecta; y ni siquiera mencionan MERGE
(que en realidad es el núcleo del problema, no NOEXPAND
, y no una simple actualización). Hay algunos detalles adicionales en el elemento Conectar que provocó la solución; con suerte, el artículo de KB se actualizará con más detalles en breve.
Mientras tanto, el resultado que puede ver son datos incorrectos, o mejor dicho, datos obsoletos. :¡La consulta puede mostrarle la versión anterior de las filas actualizadas! Pasé unos minutos intentando reproducir este escenario en AdventureWorks y fracasé estrepitosamente. Afortunadamente, Paul White (blog | @SQL_Kiwi) escribió una publicación destacada que describe el escenario y muestra una reproducción completa del problema.
No creo que pueda enfatizar cuán serio es esto.
Seguramente millones de clientes están usando vistas indexadas, muchos de ellos han migrado su código DML para usar MERGE
, y un gran número de ellos están en Enterprise Edition (o no lo están pero están usando NOEXPAND
pista o están haciendo referencia al índice directamente). Paul se apresuró a señalar que NOEXPAND
no es necesario para reproducir el problema en Enterprise Edition, y también descubrió muchos de los otros detalles necesarios para reproducir el error.
Esta publicación no pretende robar el protagonismo de las publicaciones de Jamie o Paul; solo un intento de reiterar la preocupación y crear conciencia sobre este tema. Si tiene la costumbre de ignorar las Actualizaciones acumulativas, optando por esperar a los Service Packs, y existe la posibilidad de que este problema pueda estar afectándolo en este momento, se lo debe a usted mismo, sin mencionar a sus partes interesadas y clientes, tomar este tema en serio.
Entonces, ¿qué debes hacer?
Bueno, lo que haga a continuación depende de la versión y edición de SQL Server que esté ejecutando y de si el error realmente lo afecta (o podría afectarlo).
- Debe actualizar a la última actualización acumulativa para su sucursal:
Sucursal Fijo en CU Construir Construcción mínima requerida
para aplicar la actualizaciónArtículo de KB
(Descargar)Paquete de servicio 3 de 2008 CU #8 10.00.5828 10.00.5500 KB n.º 2771833 Paquete de servicio 1 de 2008 R2 CU #10 10.50.2868 10.50.2500 KB n.º 2783135 2008 R2 Service Pack 2 CU #4 10.50.4270 10.00.4000 KB n.º 2777358 RTM 2012 CU #5 11.00.2395 11.00.2100 KB #2777772 Paquete de servicio 1 de 2012 CU #2 11.00.3339 11.00.3000 KB n.º 2790947 Tabla 1:Compilaciones que contienen la corrección
- Si no aplica la corrección, debe probar todas las referencias a sus vistas para validar que arrojan resultados correctos en todos los casos, incluso después de haber actualizado las tablas base usando
MERGE
. Si no es así (o sospecha que podrían verse afectados más adelante), debe reconstruir el índice agrupado en todas las vistas afectadas (o reparar las vistas indexadas usandoDBCC CHECKTABLE
, como Paul ha descrito en su publicación), y deja de usarMERGE
contra estas tablas hasta que haya aplicado la solución. Si continúa usandoMERGE
contra las tablas base, prepárese para continuar reparando las vistas para evitar el problema.
- Una solución más rápida sería evitar que se use la vista indexada dañada, utilizando cualquiera de los siguientes métodos requeridos:
- aplicar la sugerencia de consulta
OPTION (EXPAND VIEWS)
a todas las consultas relevantes; - eliminar cualquier referencia explícita al índice en la vista;
- en las ediciones estándar u otras en las que las vistas indexadas no coinciden automáticamente, elimine todas las instancias de
NOEXPAND
.
Pero esto, por supuesto, anularía en gran medida el propósito de la vista indexada; también puede eliminar el índice. Dicho esto, generalmente es mejor obtener los resultados correctos lentamente que obtener los resultados incorrectos rápidamente; así que tal vez esté bien.
- aplicar la sugerencia de consulta
Servidor SQL 2008 SP3
Servidor SQL 2008 R2 SP1/SP2
Servidor SQL 2012 RTM/SP1
Sus opciones si está en una de estas compilaciones:
SQL Server 2008 RTM/SP1/SP2
SQL Server 2008 R2 RTM
Desafortunadamente, tiene una versión que ya no tiene soporte general y es poco probable que este problema se solucione (a menos que tenga soporte extendido y haga mucho ruido). Por lo tanto, sus opciones están limitadas aquí:muévase a una sucursal admitida según la tabla anterior y aplique la Actualización acumulativa, o elija una de las otras opciones mencionadas anteriormente.
Servidor SQL 2000
Servidor SQL 2005
Bueno, la mala noticia es que también estás en una compilación que ya no es compatible. La buena noticia es que en este caso específico no importa:no puede usar MERGE
de todos modos, este error no puede afectarte.
Otros problemas de MERGE
Lamentablemente, esto está lejos de ser el primer error que hemos visto con MERGE
, y probablemente no será el último. Aquí hay una selección rápida de una docena MERGE
errores que todavía están marcados como activos en Connect:
- #773895:MERGE informa incorrectamente infracciones de clave única
- #766165:MERGE evalúa el índice filtrado por fila, no la operación de publicación, lo que provoca una infracción del índice filtrado
- #723696 :Upsert básico de MERGE que causa interbloqueos
- #713699:Ha fallado una verificación de aserción del sistema ("cxrowset.cpp":1528)
- #699055:Los planes de consulta MERGE permiten infracciones de las restricciones FK y CHECK
- #685800:DELETE y MERGE parametrizados Permitir violaciones de restricciones de clave foránea
- #654746:la fusión en SQL2008 SP2 todavía sufre de "Intento de establecer el valor de una columna que no admite NULL en NULL"
- #635778 :Las partes NOT MATCHED y MATCHED de una instrucción SQL MERGE no están optimizadas
- #633132:FUSIONAR CON FUENTE FILTRADA no funciona correctamente
- #596086 :error en la instrucción MERGE cuando se usa INSERT/DELETE y se filtra el índice
- #583719:la declaración MERGE trata incorrectamente las columnas calculadas que no aceptan valores NULL en algunos escenarios
- #539084:MERGE Stmt:la condición de búsqueda en una columna sin clave y un ORDER BY en la tabla derivada de la fuente rompe MERGE por completo
Ahora, puede darse el caso de que algunos de estos errores se hayan solucionado, pero su estado sea incorrecto porque el bucle de regreso a Connect no se ha cerrado. Incluso si ese es el caso, no puede ser cierto para todos ellos (y potencialmente para otros que no descubrí).
Además, Dan Guzmán ha demostrado que MERGE
no es inmune a las condiciones de carrera y otros problemas de concurrencia. La solución es usar HOLDLOCK
(o un nivel de aislamiento superior); sin embargo, es un error común pensar que MERGE
es completamente atómico y no es propenso a este problema en absoluto. Por lo tanto, me preguntaré en voz alta:¿cuántos MERGE
declaraciones por ahí incluyen HOLDLOCK
(o se están ejecutando bajo SERIALIZABLE
)? ¿Cuántos han sido probados exhaustivamente por problemas relacionados con la concurrencia?
Conclusión
Personalmente, creo que la sintaxis es excelente (aunque difícil de aprender), pero cada vez que surge un problema, mi confianza en la practicidad de reemplazar el DML existente con la nueva construcción se erosiona.
Con eso en mente, no quiero ser Chicken Little, pero no me sentiría cómodo recomendando a nadie que use MERGE
a menos que implementen pruebas extremadamente exhaustivas. Algunos de estos problemas también están presentes con UPSERT
estándar metodologías, pero los problemas son más evidentes allí. MERGE
, simplemente a través de su naturaleza de declaración única, te hace querer creer en la magia. Tal vez algún día funcione, pero en este momento sé que no podrá serrar a una persona por la mitad sin una ayuda seria.