У меня есть хранимая процедура, которая выполняет MERGE
заявление .
Кажется, что при выполнении слияния по умолчанию блокируется вся таблица.
Я вызываю эту хранимую процедуру внутри транзакции, где я также делаю некоторые другие вещи, и я хотел бы, чтобы она блокировала только затронутые строки.
Я попробовал подсказку, MERGE INTO myTable WITH (READPAST)
и она, казалось, стала меньше. Но в документе MS было предупреждение о том, что он может вставлять дубликаты ключей, минуя даже первичный ключ.
Вот моя схема таблицы:
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
Вот моя хранимая процедура:
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
Вот как я наблюдаю за блокировкой:
begin tran
EXEC MergeTest 1, 1
А потом в другой сессии:
EXEC MergeTest 2, 2
Второй сеанс ожидает завершения первого, прежде чем продолжить.
sql-server
sql-server-2008
merge
Джон Бьюкенен
источник
источник
WITH (READPAST)
инструктирует SQL Server просто пропускать строки, заблокированные другими сеансами. Вы уверены, что хотите это сделать? Кроме того, сколько строк в этой таблице вы изменяете? Покажите нам схему таблицы (включая индексы) иMERGE
оператор, который вы выполняете.Ответы:
Вам нужно дать обработчику запросов более эффективный путь доступа для поиска
StudentTotalMarks
записей. Как написано, запрос требует полного сканирования таблицы с остаточным предикатом,[StudentID] = [@StudentId]
примененным к каждой строке:Движок принимает
U
(обновляет) блокировки при чтении в качестве основной защиты от общей причины тупиков конверсии. Это поведение означает вторые блоки выполнения при попытке получитьU
блокировку для строки, уже заблокированнойX
(исключительной) блокировкой при первом выполнении.Следующий индекс обеспечивает лучший путь доступа, избегая ненужных
U
блокировок:План запроса теперь включает в себя операцию поиска
StudentID = [@StudentId]
, поэтомуU
блокировки запрашиваются только для целевых строк:Индекс не обязателен для
UNIQUE
решения рассматриваемой проблемы (хотяINCLUDE
он необходим, чтобы сделать его индексом покрытия для этого запроса).Создание из таблицы также позволит решить проблему пути доступа (и , по- видимому лишние колонки могут быть удалены). Вы должны всегда применять альтернативные ключи с ограничением или (и избегать добавления бессмысленных суррогатных ключей без уважительной причины).
StudentID
PRIMARY KEY
StudentTotalMarks
Id
UNIQUE
PRIMARY KEY
источник