Cách nhận SQL chèn và / hoặc cập nhật để không khóa toàn bộ bảng trên MS SQL Server


13

Rất nhiều người mới làm việc trên DB, vì vậy hãy đánh giá cao sự kiên nhẫn của bạn với một câu hỏi cơ bản. Tôi đang chạy SQL Server 2014 trên máy cục bộ của mình và tôi có một bảng nhỏ và ứng dụng khách cơ bản để kiểm tra các phương pháp khác nhau. Tôi nhận được những gì dường như là một khóa bảng trong cả hai INSERT INTOUPDATEbáo cáo. Máy khách là một ứng dụng ASP.NET có mã sau:

OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();

Tôi chạy mã này, sau đó từ phòng quản lý tôi chạy SELECT * FROM LAYOUTSv2. Trong cả hai trường hợp khi luồng máy khách bị tạm dừng (tức là trước khi xác nhận / rollback), truy vấn SELECT bị treo cho đến khi xảy ra cam kết / rollback.

Bảng có trường LAYOUTS_key được gán làm khóa chính. Trong cửa sổ thuộc tính, nó cho thấy nó là duy nhất và được nhóm, với khóa trang và khóa hàng đều được phép. Cài đặt leo thang khóa cho bảng là Vô hiệu hóa ... Tôi đã thử cả hai cài đặt có sẵn khác của Bảng và TỰ ĐỘNG mà không có thay đổi. Tôi đã thử SELECT ... WITH (NOLOCK)và điều đó trả về một kết quả ngay lập tức, nhưng như được cảnh báo ở đây và những nơi khác, đó không phải là điều tôi nên làm. Tôi đã thử đưa ra ROWLOCKgợi ý cho cả hai INSERTvà các UPDATEtuyên bố, nhưng không có gì thay đổi.

Hành vi tôi đang tìm kiếm là: trước khi cam kết INSERT, các truy vấn từ các luồng khác đọc tất cả các hàng ngoại trừ một hàng đang được chỉnh sửa INSERT. Trước khi cam kết UPDATEtruy vấn từ các luồng khác, hãy đọc phiên bản bắt đầu của hàng đang được chỉnh sửa UPDATE. Có cách nào tôi có thể làm điều này? Nếu tôi cần cung cấp thông tin khác để làm rõ trường hợp sử dụng của mình xin vui lòng cho tôi biết. Cảm ơn.


3
Nhân tiện WHERE LAYOUTS_key='" + newkey + "'là hoàn toàn không có vì nhiều lý do bao gồm cả SQL tiêm, bạn nên sử dụng các truy vấn được tham số hóa.
Martin Smith

1
@MartinSmith Cảm ơn bạn đã ủng hộ điều này ... chưa bao giờ nghe về các truy vấn được tham số hóa hoặc các cuộc tấn công SQL Injection.
John Riehl

@JohnRiehl, re: tấn công tiêm, hãy tưởng tượng nếu người dùng của bạn đặt newkeythành " something';DELETE FROM LAYOUTSv2 --". Bản cập nhật của bạn sẽ hoàn tất thành công và sau đó làm trống bảng vì người dùng đã thao tác truy vấn bằng cách chèn dấu nháy đơn. Thông thường, một truy vấn được tham số hóa trông giống như UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key=?, sau đó bạn gán riêng (các) giá trị cho ?(tham số) trong mã của bạn.
Daniel Hutmacher

Câu trả lời:


10

Rất có thể nó không khóa "toàn bộ bàn".

Nó đang khóa một hàng trong bảng nhưng bạn SELECT * FROM LAYOUTSv2cố gắng đọc toàn bộ bảng để nhất thiết bị chặn bởi khóa đó.

Đối với trường hợp chèn, bạn chỉ có thể chỉ định READPASTgợi ý để bỏ qua hàng bị khóa - tuy nhiên điều đó sẽ không mang lại kết quả mong muốn cho UPDATEtrường hợp đó (nó sẽ bỏ qua hàng một lần nữa không đọc phiên bản bắt đầu của hàng).

Nếu bạn định cấu hình cơ sở dữ liệu để đọc cách ly ảnh chụp đã cam kết, điều này sẽ mang lại hiệu quả mong muốn cho cả hai trường hợp (với chi phí sử dụng nhiều hơn tempdb)


Tôi đã thay đổi "Đã đọc Ảnh chụp cam kết" thành True và bây giờ nó hoạt động hoàn hảo mà không cần gợi ý. Cảm ơn! Một lần theo dõi ... Tôi đã đặt "Cho phép cách ly ảnh chụp nhanh" thành Sai ... có ổn không? Cảm ơn.
John Riehl

@JohnRiehl - Có nếu bạn không rõ ràng sử dụng SNAPSHOTcách ly tốt nhất để tắt nó và sau đó kích hoạt nó nếu sau đó bạn quyết định điều này sẽ hữu ích cho bạn.
Martin Smith

7

Các câu lệnh chèn và cập nhật được cho là để tạo các khóa cấp hàng. Tuy nhiên, khi số lượng khóa trong bất kỳ giao dịch nào là 5.000 hoặc nhiều hơn thì sự leo thang khóa xảy ra và nó tạo ra khóa cấp bảng. Vui lòng xem bên dưới.

https://technet.microsoft.com/en-us/l Library / ms184286 (v = sql.105) .aspx


Không liên quan đến câu hỏi này vì cả hai câu lệnh INSERT và UPDATE đều viết một hàng duy nhất
Martin Smith
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.