Bloquear CREAR TABLA

19

En otra aplicación, me llamó la atención el mal diseño: varios subprocesos ejecutan un EnsureDatabaseSchemaExists()método simultáneamente, que se ve básicamente así:

IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'MyTable') AND type = N'U') BEGIN

    CREATE TABLE MyTable ( ... );

END

Sin embargo, incluso si se ejecuta en una transacción SERIALIZABLE, este código no parece ser seguro para subprocesos (es decir, el código paralelo intenta crear la tabla varias veces). ¿Hay alguna posibilidad de forzar a la instrucción SELECT a adquirir un bloqueo que evite que otro subproceso haga la misma instrucción SELECT?

¿Existe un mejor patrón para los métodos multi-thread-GuaranteeSchemaExists ()?

DR
fuente

Respuestas:

18

Lo mejor es usar una transacción que contenga explícitamente y adquirir un bloqueo exclusivo personalizado para proteger toda la operación ( SELECTy CREATE TABLE) usando sp_getapplock . Los objetos del sistema no cumplen con las solicitudes de nivel de aislamiento y usan bloqueos de la misma manera que las tablas de usuario, por diseño.

La condición de carrera en el código original es que múltiples hilos pueden concluir que la tabla no existe antes de que ningún hilo llegue a la CREATE TABLEdeclaración.

Paul White dice GoFundMonica
fuente
66
+1 solo asegúrate de que el bloqueo de aplicaciones envuelva la verificación SELECCIONAR . De lo contrario, introducirá puntos muertos. Lo ideal sería obtener el bloqueo de la aplicación en modo S, verificar, la actualización a X, pero eso es complicado (por decir lo menos ...). La opción más segura es adquirir X, luego hacer todo el despliegue del esquema DB. Debería ser una operación rara (por ejemplo, al iniciar la aplicación), por lo que el bloqueo X no debería importar tanto.
Remus Rusanu
12

Mi recomendación sería hacer un mejor esfuerzo de prueba / captura. Maneje el caso duplicado explícitamente, según corresponda, por ejemplo. ignoralo...

La verdadera pregunta: ¿por qué DDL se ejecuta bajo demanda, desde múltiples xacts? Normalmente, la actualización y la migración son un asunto serio, manejado en ventanas de tiempo dedicado ... No desea que su migración (¿código primero?) Se inicie inesperadamente, algunos de esos pasos de actualización pueden llevar horas en una mesa grande (tamaño de -operaciones de datos ...)

Remus Rusanu
fuente
3
El código es algún tipo de DatabaseLogger que crea sus tablas a pedido. Sin migración, sin negocios divertidos. Sin embargo, tienes toda la razón. Voy a refactorizar el código apropiadamente.
DR
44
También considere que la implementación / configuración está perfectamente bien para ejecutarse en un contexto de privilegios elevados (por ejemplo, por un administrador), pero las operaciones normales no lo son. Actualmente se requiere CREATE TABLEsubvención para operaciones normales ...
Remus Rusanu