Bloquear CREATE TABLE

19

Em outro aplicativo, fiquei impressionado com o design ruim: vários threads executam um EnsureDatabaseSchemaExists()método simultaneamente, que se parece basicamente com isso:

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

    CREATE TABLE MyTable ( ... );

END

No entanto, mesmo se executado em uma transação SERIALIZABLE, esse código não parece seguro para threads (ou seja, o código paralelo tenta criar a tabela várias vezes). Existe alguma chance de forçar a instrução SELECT a adquirir um bloqueio que impede que outro thread faça a mesma instrução SELECT?

Existe um padrão melhor para métodos Multi-threaded-GuaranteSchemaExists ()?

DR
fonte

Respostas:

18

A melhor opção é usar uma transação contendo explícita e adquirir um bloqueio exclusivo personalizado para proteger toda a operação ( SELECTe CREATE TABLE) usando sp_getapplock . Os objetos do sistema não respeitam solicitações de nível de isolamento e usam bloqueios da mesma maneira que as tabelas do usuário, por design.

A condição de corrida no código original é que vários threads podem concluir que a tabela não existe antes que qualquer thread chegue até a CREATE TABLEinstrução.

Paul White diz que a GoFundMonica
fonte
6
+1 apenas certifique-se de que o aplicativo faça a verificação SELECT . Caso contrário, você apresentará impasses. O ideal seria obter o bloqueio do aplicativo no modo S, verifique a atualização para o X, mas isso é complicado (para dizer o mínimo ...). A opção mais segura é adquirir o X e fazer toda a implantação do esquema do banco de dados. Deve ser uma operação rara (por exemplo, na inicialização do aplicativo), portanto o bloqueio X não deve importar muito.
Remus Rusanu
12

Minha recomendação seria fazer um melhor esforço de tentativa / captura. Manipule o caso duplicado explicitamente, conforme apropriado, por exemplo. ignore isto...

A verdadeira questão: por que o DDL está sendo executado sob demanda, de vários xacts? Normalmente, a atualização e a migração são um assunto sério, tratadas em janelas de tempo dedicadas ... Você não deseja que sua migração (com o código primeiro?) Seja iniciada inesperadamente, algumas dessas etapas de atualização podem levar horas em uma grande mesa (tamanho de operações de dados ...)

Remus Rusanu
fonte
3
O código é algum tipo de DatabaseLogger que cria suas tabelas sob demanda. Sem migração, nenhum negócio engraçado. No entanto, você está completamente certo. Vou refatorar o código adequadamente.
DR
4
Considere também que a implantação / configuração é perfeitamente aceitável para executar em um contexto de privilégios elevados (por exemplo, por um administrador), mas as operações normais não são. Atualmente, você está exigindo uma CREATE TABLEconcessão para operações normais ...
Remus Rusanu