Tengo un procedimiento almacenado que realiza una MERGE
declaración .
Parece que bloquea toda la tabla de forma predeterminada al realizar la fusión.
Llamo a este procedimiento almacenado dentro de una transacción donde también estoy haciendo otras cosas y deseo que solo bloquee las filas afectadas.
Probé la pista MERGE INTO myTable WITH (READPAST)
y pareció bloquearse menos. Pero había una advertencia en el documento de ms que decía que podía insertar claves duplicadas, omitiendo incluso la clave primaria.
Aquí está mi esquema de tabla:
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
Aquí está mi procedimiento almacenado:
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
Así es como estoy observando el bloqueo:
begin tran
EXEC MergeTest 1, 1
Y luego en otra sesión:
EXEC MergeTest 2, 2
La segunda sesión espera a que se complete la primera antes de continuar.
sql-server
sql-server-2008
merge
John Buchanan
fuente
fuente
WITH (READPAST)
indica a SQL Server que simplemente omita las filas que están bloqueadas por otras sesiones. ¿Estás seguro de que quieres hacer eso? Además, ¿cuántas filas en esta tabla está modificando? Muéstrenos el esquema de la tabla (incluidos los índices) y laMERGE
declaración que está ejecutando.Respuestas:
Debe proporcionar al procesador de consultas una ruta de acceso más eficiente para ubicar los
StudentTotalMarks
registros. Tal como está escrito, la consulta requiere un análisis completo de la tabla con un predicado residual[StudentID] = [@StudentId]
aplicado a cada fila:El motor toma
U
(actualiza) bloqueos cuando lee como una defensa básica contra una causa común de bloqueos de conversión. Este comportamiento significa que el segundo bloque de ejecución al intentar obtener unU
bloqueo en la fila ya bloqueado con unX
bloqueo (exclusivo) en la primera ejecución.El siguiente índice proporciona una mejor ruta de acceso, evitando
U
bloqueos innecesarios :El plan de consulta ahora incluye una operación de búsqueda activada
StudentID = [@StudentId]
, por lo que losU
bloqueos solo se solicitan en las filas de destino:No se requiere que el índice sea
UNIQUE
para resolver el problema en cuestión (aunqueINCLUDE
se requiere para que sea un índice de cobertura para esta consulta).Haciendo
StudentID
elPRIMARY KEY
de laStudentTotalMarks
tabla también se resolvería el problema del camino de acceso (y el parecer redundanteId
columna podría ser eliminado). Siempre debe aplicar claves alternativas con una restricciónUNIQUE
oPRIMARY KEY
(y evitar agregar claves sustitutas sin sentido sin una buena razón).fuente