Preciso saber se o padrão a seguir requer que eu o use HOLDLOCK
em um ambiente altamente concorrente. Observe particularmente que source
não é outra tabela. São basicamente parâmetros que foram passados para a consulta.
MERGE INTO table1 WITH (HOLDLOCK) AS target
USING (
SELECT
@ID AS ID,
...
) AS source
ON (target.ID = source.ID AND ...)
WHEN NOT MATCHED THEN
INSERT (ID, ...)
VALUES (source.ID, ...)
Eu só o coloquei por precaução, já que tenho lido sobre as armadilhas do MERGE
. No meu próprio teste de desenvolvimento (ainda muito altamente concorrente), não parece fazer diferença. Nunca tive problemas de simultaneidade, mesmo sem o HOLDLOCK
.
Não posso usar INSERT INTO table1 ... WHERE ... DOES NOT EXISTS (... SELECT table1 ...)
o padrão, porque isso gera problemas de concorrência, mesmo com o HOLDLOCK
in place. Então, essa MERGE
foi minha solução para isso, só não tenho certeza se preciso disso HOLDLOCK
.
A
HOLDLOCK
dica aplicaSERIALIZABLE
semântica de isolamento à tabela sugerida. Isso é necessário quando você deseja inserir uma linha somente se nenhuma linha com a mesma chave existir atualmente, por exemplo.O problema subjacente é o
MERGE
teste para verificar se uma linha específica não existe e se essa condição continua válida até que a inserção seja concluída.Sem semântica serializável, não há linha para bloquear para fornecer a garantia necessária. O bloqueio de intervalo de chaves fornece a solução no SQL Server ao bloquear o intervalo de chaves ao qual qualquer nova linha seria adicionada. Isso só está disponível sob isolamento serializável.
Uma
INSERT
declaração separada está sujeita às mesmas considerações fundamentais e, portanto, também requer uma dica de nível de isolamento para comportamento correto sob alta simultaneidade.Note que no seu exemplo, a tabela de destino também é acessada para leitura de acordo com as cláusulas
ON
andWHERE NOT MATCHED
. É aqui que o bloqueio de intervalo é necessário para garantir que qualquer linha que não corresponda continue a não existir até que a inserção aconteça.Não há detalhes suficientes na pergunta para dizer por que você
INSERT
tem problemas de simultaneidade (presumivelmente, violações de chave exclusiva), masMERGE
não. O diabo está sempre nos detalhes. Talvez você tenha tido sorte. Talvez os IDs a serem inseridos sejam genuinamente sempre disjuntos em seusMERGE
testes.De qualquer forma, sim, o 'padrão' requer uma
SERIALIZABLE
dica para ser seguro para inserções simultâneas de uma única linha. Inserções de várias linhas sempre correm o risco de um deadlock se a ordem das linhas for infeliz. Padrões à parte, é melhor entender o motivo da dica do que aplicá-la apenas por hábito.Se suas sessões simultâneas que executam essas inserções têm a garantia de não receber o mesmo valor de ID, a dica não é necessária. Pergunte a si mesmo se essa garantia é realmente sólida agora e continuará a ser para sempre.
A propósito,
HOLDLOCK
é um nome terrível para essa dica e mantido apenas para compatibilidade com versões anteriores. O sinônimo mais moderno éSERIALIZABLE
.Por fim, isso parece estranho:
Você deve usar a cláusula somente para determinar se as linhas de origem e destino correspondem. A coluna ID parece que deveria ser um identificador exclusivo. No é necessário nesse caso e pode ser um erro.
ON
AND
Perguntas e respostas relacionadas: Problema de entrada simultânea do SQL Server 2014 (inclui links para uma pesquisa de métodos)