Eu tenho um procedimento armazenado que executa uma MERGE
instrução .
Parece que bloqueia a tabela inteira por padrão ao executar a mesclagem.
Estou chamando esse procedimento armazenado dentro de uma transação em que também estou fazendo outras coisas e gostaria que ele apenas bloqueasse as linhas afetadas.
Eu tentei a dica MERGE INTO myTable WITH (READPAST)
e parecia travar menos. Mas havia um aviso no ms doc que dizia que ele poderia inserir chaves duplicadas, ignorando até a chave primária.
Aqui está o meu esquema de tabela:
CREATE TABLE StudentDetails
(
StudentID INTEGER PRIMARY KEY,
StudentName VARCHAR(15)
)
GO
INSERT INTO StudentDetails
VALUES(1,'WANG')
INSERT INTO StudentDetails
VALUES(2,'JOHNSON')
GO
CREATE TABLE StudentTotalMarks
(
Id INT IDENTITY PRIMARY KEY,
StudentID INTEGER REFERENCES StudentDetails,
StudentMarks INTEGER
)
GO
INSERT INTO StudentTotalMarks
VALUES(1,230)
INSERT INTO StudentTotalMarks
VALUES(2,255)
GO
Aqui está o meu procedimento armazenado:
CREATE PROCEDURE MergeTest
@StudentId int,
@Mark int
AS
WITH Params
AS
(
SELECT @StudentId as StudentId,
@Mark as Mark
)
MERGE StudentTotalMarks AS stm
USING Params p
ON stm.StudentID = p.StudentId
WHEN MATCHED AND stm.StudentMarks > 250 THEN DELETE
WHEN MATCHED THEN UPDATE SET stm.StudentMarks = p.Mark
WHEN NOT MATCHED THEN
INSERT(StudentID,StudentMarks)
VALUES(p.StudentId, p.Mark);
GO
Aqui está como eu estou observando o bloqueio:
begin tran
EXEC MergeTest 1, 1
E então em outra sessão:
EXEC MergeTest 2, 2
A segunda sessão aguarda a conclusão da primeira antes de continuar.
sql-server
sql-server-2008
merge
John Buchanan
fonte
fonte
WITH (READPAST)
instrui o SQL Server a ignorar apenas as linhas bloqueadas por outras sessões. Você tem certeza que deseja fazer isso? Além disso, quantas linhas nesta tabela você está modificando? Mostre-nos o esquema da tabela (incluindo índices) e aMERGE
instrução que você está executando.Respostas:
Você precisa dar ao processador de consultas um caminho de acesso mais eficiente para localizar
StudentTotalMarks
registros. Conforme escrito, a consulta requer uma varredura completa da tabela com um predicado residual[StudentID] = [@StudentId]
aplicado a cada linha:O mecanismo usa
U
bloqueios (de atualização) ao ler como uma defesa básica contra uma causa comum de conflitos de conversão. Esse comportamento significa os segundos blocos de execução ao tentar obter umU
bloqueio na linha já bloqueada com umX
bloqueio (exclusivo) pela primeira execução.O índice a seguir fornece um melhor caminho de acesso, evitando
U
bloqueios desnecessários :O plano de consulta agora inclui uma operação de busca ativada
StudentID = [@StudentId]
, portanto, osU
bloqueios são solicitados apenas nas linhas de destino:O índice não é exigido para ser
UNIQUE
para resolver o problema na mão (embora oINCLUDE
é necessário para torná-lo um índice de cobertura para esta consulta).Fazer
StudentID
oPRIMARY KEY
daStudentTotalMarks
mesa também resolver o problema do caminho de acesso (e aparentemente redundanteId
coluna podia ser removido). Você deve sempre aplicar chaves alternativas com uma restriçãoUNIQUE
ouPRIMARY KEY
(e evitar adicionar chaves substitutas sem sentido, sem uma boa razão).fonte