Chúng tôi đang thấy một số điều kiện deadlock nguy hiểm, nhưng hiếm gặp, trong cơ sở dữ liệu Stack Overflow SQL Server 2005.
Tôi đã đính kèm hồ sơ, thiết lập hồ sơ theo dõi bằng cách sử dụng bài viết tuyệt vời này về cách khắc phục sự cố bế tắc và nắm bắt một loạt các ví dụ. Điều kỳ lạ là cách viết của deadlock luôn giống nhau :
UPDATE [dbo].[Posts]
SET [AnswerCount] = @p1, [LastActivityDate] = @p2, [LastActivityUserId] = @p3
WHERE [Id] = @p0
Câu lệnh deadlocking khác khác nhau, nhưng nó thường là một số kiểu đọc đơn giản, tầm thường của bảng bài viết. Cái này luôn bị giết trong bế tắc. Đây là một ví dụ
SELECT
[t0].[Id], [t0].[PostTypeId], [t0].[Score], [t0].[Views], [t0].[AnswerCount],
[t0].[AcceptedAnswerId], [t0].[IsLocked], [t0].[IsLockedEdit], [t0].[ParentId],
[t0].[CurrentRevisionId], [t0].[FirstRevisionId], [t0].[LockedReason],
[t0].[LastActivityDate], [t0].[LastActivityUserId]
FROM [dbo].[Posts] AS [t0]
WHERE [t0].[ParentId] = @p0
Để hoàn toàn rõ ràng, chúng ta không nhìn thấy các bế tắc ghi / ghi, mà là đọc / ghi.
Hiện tại, chúng tôi có một hỗn hợp các truy vấn LINQ và SQL được tham số hóa. Chúng tôi đã thêm with (nolock)
vào tất cả các truy vấn SQL. Điều này có thể đã giúp một số. Chúng tôi cũng có một truy vấn huy hiệu viết kém (rất) mà tôi đã sửa hôm qua, mất tới 20 giây để chạy mọi lúc và đang chạy mỗi phút trên đó. Tôi đã hy vọng đây là nguồn gốc của một số vấn đề về khóa!
Thật không may, tôi gặp một lỗi bế tắc khác khoảng 2 giờ trước. Cùng một triệu chứng chính xác, cùng một thủ phạm chính xác viết.
Điều thực sự kỳ lạ là câu lệnh SQL ghi khóa mà bạn thấy ở trên là một phần của một đường dẫn mã rất cụ thể. Nó chỉ được thực thi khi câu trả lời mới được thêm vào câu hỏi - nó cập nhật câu hỏi chính với số câu trả lời mới và ngày / người dùng cuối cùng. Rõ ràng đây không phải là điều phổ biến so với số lượng lớn các lần đọc mà chúng tôi đang thực hiện! Theo như tôi có thể nói, chúng tôi không thực hiện số lượng ghi lớn ở bất kỳ đâu trong ứng dụng.
Tôi nhận ra rằng NOLOCK giống như một cái búa khổng lồ, nhưng hầu hết các truy vấn chúng tôi chạy ở đây không cần phải chính xác như vậy. Bạn sẽ quan tâm nếu hồ sơ người dùng của bạn có lỗi thời vài giây không?
Sử dụng NOLOCK với Linq khó hơn một chút như Scott Hanselman thảo luận ở đây .
Chúng tôi đang tán tỉnh ý tưởng sử dụng
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
trên bối cảnh cơ sở dữ liệu cơ sở để tất cả các truy vấn LINQ của chúng tôi có bộ này. Nếu không có điều đó, chúng tôi sẽ phải gói mọi lệnh gọi LINQ mà chúng tôi thực hiện (tốt, những lệnh đọc đơn giản, chiếm phần lớn trong số chúng) trong một khối mã giao dịch 3-4 dòng, điều này thật tệ.
Tôi đoán rằng tôi hơi thất vọng khi những lần đọc tầm thường trong SQL 2005 có thể gây bế tắc khi ghi. Tôi có thể thấy bế tắc ghi / ghi là một vấn đề lớn, nhưng bạn có đọc không? Chúng tôi không điều hành một trang web ngân hàng ở đây, chúng tôi không cần độ chính xác hoàn hảo mọi lúc.
Ý tưởng? Suy nghĩ?
Bạn có đang khởi tạo một đối tượng LINQ to SQL DataContext mới cho mọi thao tác hay có lẽ bạn đang chia sẻ cùng một ngữ cảnh tĩnh cho tất cả các cuộc gọi của mình?
Jeremy, chúng tôi đang chia sẻ một văn bản dữ liệu tĩnh trong Bộ điều khiển cơ sở cho hầu hết các phần:
private DBContext _db;
/// <summary>
/// Gets the DataContext to be used by a Request's controllers.
/// </summary>
public DBContext DB
{
get
{
if (_db == null)
{
_db = new DBContext() { SessionName = GetType().Name };
//_db.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}
return _db;
}
}
Bạn có khuyên chúng tôi nên tạo bối cảnh mới cho mọi Bộ điều khiển, hoặc cho mỗi Trang, hoặc .. thường xuyên hơn không?