Lock CREATE TABLE

19

Dans une autre application, j'ai été frappé par une mauvaise conception: plusieurs threads exécutent une EnsureDatabaseSchemaExists()méthode simultanément, qui ressemble essentiellement à ceci:

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

    CREATE TABLE MyTable ( ... );

END

Cependant, même s'il est exécuté dans une transaction SERIALIZABLE, ce code ne semble pas être thread-safe (c'est-à-dire que le code parallèle essaie de créer la table plusieurs fois). Est-il possible de forcer l'instruction SELECT à acquérir un verrou qui empêche un autre thread de faire la même instruction SELECT?

Existe-t-il un meilleur modèle pour les méthodes multi-thread-EnsureSchemaExists ()?

DR
la source

Réponses:

18

Le mieux est d'utiliser une transaction contenant explicitement et d'acquérir un verrou exclusif personnalisé pour protéger l'ensemble de l'opération ( SELECTet CREATE TABLE) à l' aide de sp_getapplock . Les objets système n'honorent pas les demandes de niveau d'isolement et utilisent des verrous de la même manière que les tables utilisateur, par conception.

La condition de concurrence critique dans le code d'origine est que plusieurs threads peuvent conclure que la table n'existe pas avant qu'un thread n'atteigne l' CREATE TABLEinstruction.

Paul White dit GoFundMonica
la source
6
+1 assurez-vous simplement que l'applock encapsule la vérification SELECT . Sinon, vous introduirez des blocages. Idéalement, on obtiendrait le verrouillage de l'application en mode S, vérifiez, la mise à niveau vers X, mais c'est délicat (pour le moins ...). L'option la plus sûre consiste à acquérir X, puis à effectuer l'intégralité du déploiement du schéma de base de données. Cela devrait être une opération rare (par exemple au démarrage de l'application), donc le verrou X ne devrait pas avoir autant d'importance.
Remus Rusanu
12

Ma recommandation serait de faire de son mieux pour essayer / attraper. Traitez le cas en double de manière explicite, le cas échéant, par exemple. ignorez-le ...

La vraie question: pourquoi DDL fonctionne-t-il à la demande, à partir de plusieurs xacts? Normalement, la mise à niveau et la migration sont un problème sérieux, géré dans des fenêtres de temps dédiées ... Vous ne voulez pas que votre migration (code en premier?) Se déclenche de manière inattendue, certaines de ces étapes de mise à jour peuvent prendre des heures sur une grande table (taille de -opérations de données ...)

Remus Rusanu
la source
3
Le code est une sorte de DatabaseLogger qui crée ses tables à la demande. Pas de migration, pas de drôles d'affaires. Cependant, vous avez tout à fait raison. Je vais refactoriser le code de manière appropriée.
DR
4
Considérez également que le déploiement / la configuration est parfaitement OK pour fonctionner sur un contexte de privilèges élevés (par exemple par un administrateur), mais pas les opérations normales. Actuellement, vous avez besoin d'une CREATE TABLEsubvention pour des opérations normales ...
Remus Rusanu