Saya memiliki prosedur tersimpan yang melakukan MERGE
pernyataan .
Sepertinya itu mengunci seluruh tabel secara default saat melakukan penggabungan.
Saya memanggil prosedur tersimpan ini di dalam transaksi di mana saya juga melakukan beberapa hal lain dan saya berharap itu hanya akan mengunci baris yang terpengaruh.
Saya mencoba petunjuknya MERGE INTO myTable WITH (READPAST)
dan sepertinya kurang mengunci. Tetapi ada peringatan di ms doc yang mengatakan itu bisa memasukkan kunci duplikat, melewati bahkan kunci utama.
Berikut adalah skema tabel saya:
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
Ini adalah prosedur tersimpan saya:
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
Inilah cara saya mengamati penguncian:
begin tran
EXEC MergeTest 1, 1
Dan kemudian di sesi lain:
EXEC MergeTest 2, 2
Sesi kedua menunggu yang pertama selesai sebelum melanjutkan.
sql-server
sql-server-2008
merge
John Buchanan
sumber
sumber
WITH (READPAST)
menginstruksikan SQL Server untuk hanya melewati baris yang dikunci oleh sesi lain. Anda yakin ingin melakukan itu? Juga, berapa banyak baris dalam tabel ini yang Anda modifikasi? Tunjukkan kami skema tabel (termasuk indeks) danMERGE
pernyataan yang Anda jalankan.Jawaban:
Anda perlu memberi jalur akses yang lebih efisien kepada prosesor kueri untuk menemukan
StudentTotalMarks
catatan. Seperti yang tertulis, permintaan membutuhkan pemindaian penuh tabel dengan predikat residual yang[StudentID] = [@StudentId]
diterapkan untuk setiap baris:Mesin mengambil
U
(memperbarui) kunci saat membaca sebagai pertahanan dasar terhadap penyebab umum kebuntuan konversi. Perilaku ini berarti blok eksekusi kedua ketika mencoba untuk mendapatkanU
kunci pada baris yang sudah dikunci dengan kunciX
(eksklusif) dengan eksekusi pertama.Indeks berikut menyediakan jalur akses yang lebih baik, menghindari mengambil
U
kunci yang tidak perlu :Rencana kueri sekarang termasuk operasi pencarian aktif
StudentID = [@StudentId]
, jadiU
kunci hanya diminta pada baris target:Indeks tidak diharuskan untuk
UNIQUE
menyelesaikan masalah yang ada (meskipunINCLUDE
diperlukan untuk menjadikannya sebagai indeks penutup untuk permintaan ini).Membuat
StudentID
yangPRIMARY KEY
dariStudentTotalMarks
tabel juga akan memecahkan masalah akses jalan (dan tampaknya berlebihanId
kolom bisa dihapus). Anda harus selalu menerapkan kunci alternatif denganUNIQUE
atauPRIMARY KEY
kendala (dan menghindari menambahkan kunci pengganti yang tidak berarti tanpa alasan yang baik).sumber