sql >> Base de Datos >  >> RDS >> Database

Si está utilizando vistas indexadas y MERGE, ¡lea esto!

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 tanto UPDATE y (DELETE o INSERT ) 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).

    Servidor SQL 2008 SP3
    Servidor SQL 2008 R2 SP1/SP2
    Servidor SQL 2012 RTM/SP1

    Sus opciones si está en una de estas compilaciones:

  • 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ón

    Artí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 usando DBCC CHECKTABLE , como Paul ha descrito en su publicación), y deja de usar MERGE contra estas tablas hasta que haya aplicado la solución. Si continúa usando MERGE 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.

  • 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.