Apa opsi penguncian saya untuk pernyataan Gabung?


13

Saya memiliki prosedur tersimpan yang melakukan MERGEpernyataan .

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.


1
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) dan MERGEpernyataan yang Anda jalankan.
Nick Chammas

@NickChammas terima kasih atas bantuannya, saya memperbarui pertanyaan dengan detailnya. Saya membayangkan READPAST akan menjadi buruk ...
John Buchanan

Jawaban:


12

Anda perlu memberi jalur akses yang lebih efisien kepada prosesor kueri untuk menemukan StudentTotalMarkscatatan. Seperti yang tertulis, permintaan membutuhkan pemindaian penuh tabel dengan predikat residual yang [StudentID] = [@StudentId]diterapkan untuk setiap baris:

Rencana Pemindaian

Mesin mengambil U(memperbarui) kunci saat membaca sebagai pertahanan dasar terhadap penyebab umum kebuntuan konversi. Perilaku ini berarti blok eksekusi kedua ketika mencoba untuk mendapatkan Ukunci pada baris yang sudah dikunci dengan kunci X(eksklusif) dengan eksekusi pertama.

Indeks berikut menyediakan jalur akses yang lebih baik, menghindari mengambil Ukunci yang tidak perlu :

CREATE UNIQUE INDEX uq1 
ON dbo.StudentTotalMarks (StudentID) 
INCLUDE (StudentMarks);

Rencana kueri sekarang termasuk operasi pencarian aktif StudentID = [@StudentId], jadi Ukunci hanya diminta pada baris target:

Carilah Rencana

Indeks tidak diharuskan untuk UNIQUEmenyelesaikan masalah yang ada (meskipun INCLUDEdiperlukan untuk menjadikannya sebagai indeks penutup untuk permintaan ini).

Membuat StudentIDyang PRIMARY KEYdari StudentTotalMarkstabel juga akan memecahkan masalah akses jalan (dan tampaknya berlebihan Idkolom bisa dihapus). Anda harus selalu menerapkan kunci alternatif dengan UNIQUEatau PRIMARY KEYkendala (dan menghindari menambahkan kunci pengganti yang tidak berarti tanpa alasan yang baik).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.