Tengo un procedimiento almacenado que realiza una MERGEdeclaració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, 2La 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 laMERGEdeclaración que está ejecutando.Respuestas:
Debe proporcionar al procesador de consultas una ruta de acceso más eficiente para ubicar los
StudentTotalMarksregistros. 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 unUbloqueo en la fila ya bloqueado con unXbloqueo (exclusivo) en la primera ejecución.El siguiente índice proporciona una mejor ruta de acceso, evitando
Ubloqueos innecesarios :El plan de consulta ahora incluye una operación de búsqueda activada
StudentID = [@StudentId], por lo que losUbloqueos solo se solicitan en las filas de destino:No se requiere que el índice sea
UNIQUEpara resolver el problema en cuestión (aunqueINCLUDEse requiere para que sea un índice de cobertura para esta consulta).Haciendo
StudentIDelPRIMARY KEYde laStudentTotalMarkstabla también se resolvería el problema del camino de acceso (y el parecer redundanteIdcolumna podría ser eliminado). Siempre debe aplicar claves alternativas con una restricciónUNIQUEoPRIMARY KEY(y evitar agregar claves sustitutas sin sentido sin una buena razón).fuente