Chẩn đoán bế tắc trong SQL Server 2005


82

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?


2
Có gì <a href=" en.wikipedia.org/wiki/... mode</a> bạn đang sử dụng, "bi quan" (lock-based) hoặc "lạc quan" (<a href =" en.wikipedia.org/wiki/ … )?
John Siracusa

Tôi đồng ý với câu trả lời của Guy ở trên - thay vì cố gắng giải quyết các triệu chứng tại sao không giải quyết các nguyên nhân cơ bản? Thêm tổng số AnswerCount đang chạy vào bảng Bài đăng, bạn đã tạo một tài nguyên chặn tiềm năng. Jeff có muốn đăng ERD của mình cho StackOverflow để mọi người có thể phê bình không?
andyp

2
Chà - đã nghe về điều này trên podcast của bạn với Scott. Không thể tin được là nó không xuất xưởng với cấu hình tốt hơn. Tôi sẽ hiển thị điều này cho DBA của chúng tôi (vì họ cũng sử dụng 'nolock' rộng rãi)
Dan Esparza

3
Hãy xem: Samsaffron.com/archive/2008/08/27/Deadlocked+ để biết lý do tại sao điều này đã bị deadlock. Bật tính năng cô lập ảnh chụp nhanh là một giải pháp tốt cho vấn đề này.
Sam Saffron

Câu trả lời:


44

Theo MSDN:

http://msdn.microsoft.com/en-us/library/ms191242.aspx

Khi tùy chọn cơ sở dữ liệu READ COMMITTED SNAPSHOT hoặc ALLOW SNAPSHOT ISOLATION được BẬT, các bản sao lôgic (phiên bản) được duy trì cho tất cả các sửa đổi dữ liệu được thực hiện trong cơ sở dữ liệu. Mỗi khi một hàng được sửa đổi bởi một giao dịch cụ thể, phiên bản của Công cụ Cơ sở dữ liệu sẽ lưu trữ một phiên bản của hình ảnh đã cam kết trước đó của hàng đó trong tempdb. Mỗi phiên bản được đánh dấu bằng số thứ tự giao dịch của giao dịch đã thực hiện thay đổi. Các phiên bản của các hàng đã sửa đổi được xâu chuỗi bằng danh sách liên kết. Giá trị hàng mới nhất luôn được lưu trữ trong cơ sở dữ liệu hiện tại và được liên kết với các hàng có phiên bản được lưu trữ trong tempdb.

Đối với các giao dịch ngắn hạn, phiên bản của một hàng đã sửa đổi có thể được lưu vào bộ đệm trong vùng đệm mà không được ghi vào tệp đĩa của cơ sở dữ liệu tempdb. Nếu nhu cầu về hàng được tạo phiên bản ngắn hạn, nó sẽ đơn giản bị loại khỏi vùng đệm và có thể không nhất thiết phải chịu chi phí I / O.

Dường như có một hình phạt hiệu suất nhẹ đối với chi phí bổ sung, nhưng nó có thể không đáng kể. Chúng ta nên kiểm tra để chắc chắn.

Hãy thử đặt tùy chọn này và LOẠI BỎ tất cả các KHOẢNG CÁCH khỏi các truy vấn mã trừ khi nó thực sự cần thiết. NOLOCKs hoặc sử dụng các phương thức toàn cục trong trình xử lý ngữ cảnh cơ sở dữ liệu để chống lại các mức cô lập giao dịch cơ sở dữ liệu là Band-Aids cho vấn đề. NOLOCKS sẽ che giấu các vấn đề cơ bản với lớp dữ liệu của chúng tôi và có thể dẫn đến việc chọn dữ liệu không đáng tin cậy, trong đó lập phiên bản hàng tự động chọn / cập nhật dường như là giải pháp.

ALTER Database [StackOverflow.Beta] SET READ_COMMITTED_SNAPSHOT ON

3
"NOLOCKS sẽ che giấu các vấn đề cơ bản với lớp dữ liệu của chúng ta" ... NOLOCK che giấu những vấn đề gì? Nếu tôi nghĩ rằng tôi cần NOLOCK, tôi nên tìm những vấn đề gì?
Matt Hamilton

3
Điều gì về câu trả lời này khiến nó trở thành "câu trả lời"? Tôi vẫn không hiểu tại sao phần nghìn giây đọc lại làm chết việc ghi ngay lập tức? Tôi đoán câu trả lời của "user13484" quá tệ, không có tham chiếu đến nó nếu đúng như vậy.
RichardTheKiwi,

37

NOLOCKREAD UNCOMMITTED là một con dốc trơn trượt. Bạn không bao giờ nên sử dụng chúng trừ khi bạn hiểu tại sao bế tắc đang xảy ra trước. Tôi sẽ làm tôi lo lắng khi bạn nói, "Chúng tôi đã thêm (nolock) vào tất cả các truy vấn SQL". Cần thêm WITH NOLOCK ở mọi nơi là dấu hiệu chắc chắn rằng bạn có vấn đề trong lớp dữ liệu của mình.

Bản thân câu lệnh cập nhật có vẻ hơi có vấn đề. Bạn có xác định số lượng sớm hơn trong giao dịch hay chỉ lấy nó từ một đối tượng? AnswerCount = AnswerCount+1khi một câu hỏi được thêm vào có lẽ là một cách tốt hơn để xử lý điều này. Sau đó, bạn không cần giao dịch để có được số lượng chính xác và bạn không phải lo lắng về vấn đề đồng thời mà bạn có thể gặp phải.

Một cách dễ dàng để giải quyết loại vấn đề bế tắc này mà không cần nhiều thao tác và không cho phép đọc bẩn là sử dụng "Snapshot Isolation Mode"(mới trong SQL 2005) sẽ luôn cung cấp cho bạn việc đọc sạch dữ liệu chưa sửa đổi cuối cùng. Bạn cũng có thể nắm bắt và thử lại các câu lệnh bị khóa khá dễ dàng nếu bạn muốn xử lý chúng một cách linh hoạt.


4
Tôi với JEzell - điều đầu tiên tôi bắt đầu là 'SET AnswerCount = <giá trị cố định>'. Giá trị đó đến từ đâu? Điều đó khiến tôi tự hỏi liệu ở nơi nào khác trong giao dịch, bạn đã lấy nó theo cách lấy một đống khóa. Tôi sẽ bắt đầu với điều đó. Và vâng, NOLOCK toàn cầu là một Band-Aid.
Cowan

25

Câu hỏi OP là hỏi tại sao vấn đề này lại xảy ra. Bài đăng này hy vọng sẽ giải đáp được điều đó trong khi vẫn để những giải pháp khả thi được những người khác tìm ra.

Đây có lẽ là một vấn đề liên quan đến chỉ mục. Ví dụ, giả sử bảng Bài viết có chỉ mục X không phân cụm chứa ParentID và một (hoặc nhiều) trường đang được cập nhật (AnswerCount, LastActivityDate, LastActivityUserId).

Bế tắc sẽ xảy ra nếu cmd CHỌN thực hiện khóa đọc chia sẻ trên chỉ mục X để tìm kiếm bởi ParentId và sau đó cần thực hiện khóa đọc chia sẻ trên chỉ mục được phân cụm để lấy các cột còn lại trong khi cmd CẬP NHẬT thực hiện khóa không ghi khóa chỉ mục được phân nhóm và cần có khóa không ghi trên chỉ mục X để cập nhật nó.

Bây giờ bạn có một tình huống trong đó A khóa X và đang cố gắng lấy Y trong khi B khóa Y và cố gắng lấy X.

Tất nhiên, chúng tôi sẽ cần OP cập nhật bài đăng của anh ấy với thêm thông tin về các chỉ số đang hoạt động để xác nhận xem đây có thực sự là nguyên nhân hay không.


Tôi đồng ý với phân tích này - CHỌN và CẬP NHẬT đang xử lý các hàng theo một thứ tự khác nhau, vì vậy mỗi hàng đang cố gắng lấy một khóa hàng mà hàng kia có.
Mike Dimmick 17/09/08

Đây là phản hồi tốt nhất cho toàn bộ chuỗi này và đưa ra lời giải thích duy nhất về lý do thực sự xảy ra bế tắc. Tệ nó không phải là câu trả lời số 1 bởi vì nó là câu trả lời tốt nhất ở đây.
Jonathan Kehayias

Một số câu trả lời thiếu điểm về khóa giữa 2 câu lệnh đơn giản về nguyên tử. Đây là bài viết duy nhất cố gắng giải thích nó. Mặc dù câu lệnh đơn giản nhưng bản cập nhật bảng có thể liên quan đến nhiều bản cập nhật CIX và NCIX, bản cập nhật này mở rộng thành nhiều thao tác. Tương tự cho ĐỌC liên quan đến duyệt NCIX, tra cứu dấu trang CIX. Này không có gì để làm với việc gia nhập bảng theo thứ tự vv (để mọi người đọc câu hỏi ??)
RichardTheKiwi

18

Tôi khá khó chịu về câu hỏi này và câu trả lời của tiếp viên. Có rất nhiều "thử bụi ma thuật này! Không có bụi ma thuật đó!"

Tôi không thể thấy bất cứ nơi nào mà bạn đã loại bỏ các ổ khóa được lấy và xác định loại ổ khóa chính xác bị khóa.

Tất cả những gì bạn đã chỉ ra là một số khóa xảy ra - không phải là những gì đang bị khóa.

Trong SQL 2005, bạn có thể biết thêm thông tin về những ổ khóa nào đang được lấy ra bằng cách sử dụng:

DBCC TRACEON (1222, -1)

để khi bế tắc xảy ra, bạn sẽ có chẩn đoán tốt hơn.


13
Một deadlock được xử lý ngay lập tức bởi trình giám sát deadlock trong SQL Server. Các DMV vô dụng trong việc khắc phục sự cố vì nạn nhân sẽ được chọn và giết trước khi bạn có thể phát hiện ra nó đang xảy ra.
Jonathan Kehayias

14

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? Ban đầu tôi đã thử cách tiếp cận thứ hai, và từ những gì tôi nhớ, nó gây ra khóa không mong muốn trong DB. Bây giờ tôi tạo ra một bối cảnh mới cho mọi hoạt động nguyên tử.


10

Trước khi đốt nhà để bắt ruồi bằng NOLOCK, bạn có thể muốn xem qua biểu đồ bế tắc mà lẽ ra bạn nên nắm bắt bằng Profiler.

Hãy nhớ rằng một deadlock yêu cầu (ít nhất) 2 khóa. Kết nối 1 có Khóa A, muốn có Khóa B - và ngược lại cho Kết nối 2. Đây là một tình huống nan giải và ai đó phải đưa ra.

Những gì bạn đã trình bày cho đến nay được giải quyết bằng cách khóa đơn giản, điều mà Sql Server rất vui được thực hiện suốt cả ngày.

Tôi nghi ngờ bạn (hoặc LINQ) đang bắt đầu một giao dịch với câu lệnh UPDATE trong đó và CHỌN một số thông tin khác trước khi thực hiện. Tuy nhiên, bạn thực sự cần xem lại qua biểu đồ bế tắc để tìm các ổ khóa được giữ bởi mỗi luồng, sau đó quay lại thông qua Profiler để tìm các câu lệnh khiến các khóa đó được cấp.

Tôi hy vọng rằng có ít nhất 4 câu lệnh để hoàn thành câu đố này (hoặc một câu lệnh cần nhiều lần khóa - có lẽ có một trình kích hoạt trên bảng Bài viết?).


7

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?

Không - điều đó hoàn toàn có thể chấp nhận được. Đặt mức cô lập giao dịch cơ sở có lẽ là cách tốt nhất / sạch nhất để thực hiện.


5

Bế tắc đọc / ghi điển hình đến từ việc truy cập thứ tự chỉ mục. Đọc (T1) xác định vị trí hàng trên chỉ mục A và sau đó tìm kiếm cột dự kiến ​​trên chỉ mục B (thường được phân cụm). Viết (T2) thay đổi chỉ mục B (cụm) sau đó phải cập nhật chỉ số A. T1 có S-Lck trên A, muốn S-Lck trên B, T2 có X-Lck trên B, muốn U-Lck trên A. Chốt lại , phùng. T1 bị giết. Điều này phổ biến trong các môi trường có lưu lượng OLTP lớn và chỉ có một ít chỉ mục :). Giải pháp là làm cho bài đọc không phải nhảy từ A sang B (tức là cột được bao gồm trong A, hoặc loại bỏ cột khỏi danh sách dự kiến) hoặc T2 không phải nhảy từ B sang A (không cập nhật cột đã lập chỉ mục). Thật không may, linq không phải là bạn của bạn ở đây ...


BTW A và B là các chỉ mục của cùng một bảng
Remus Rusanu

3

@Jeff - Tôi chắc chắn không phải là chuyên gia về vấn đề này, nhưng tôi đã có kết quả tốt với việc tạo bối cảnh mới cho hầu hết mọi cuộc gọi. Tôi nghĩ rằng nó tương tự như việc tạo một đối tượng Kết nối mới trên mọi cuộc gọi với ADO. Chi phí không quá tệ như bạn nghĩ, vì dù sao thì tính năng gộp kết nối vẫn sẽ được sử dụng.

Tôi chỉ sử dụng một trình trợ giúp tĩnh toàn cục như thế này:

public static class AppData
{
    /// <summary>
    /// Gets a new database context
    /// </summary>
    public static CoreDataContext DB
    {
        get
        {
            var dataContext = new CoreDataContext
            {
                DeferredLoadingEnabled = true
            };
            return dataContext;
        }
    }
}

và sau đó tôi làm một cái gì đó như thế này:

var db = AppData.DB;

var results = from p in db.Posts where p.ID = id select p;

Và tôi sẽ làm điều tương tự cho các bản cập nhật. Dù sao, tôi không có nhiều lưu lượng truy cập như bạn, nhưng tôi chắc chắn bị khóa khi tôi sử dụng DataContext được chia sẻ sớm với chỉ một số ít người dùng. Không đảm bảo, nhưng nó có thể đáng để thử.

Cập nhật : Sau đó, nhìn lại mã của bạn, bạn chỉ đang chia sẻ ngữ cảnh dữ liệu trong suốt thời gian tồn tại của phiên bản bộ điều khiển cụ thể đó, về cơ bản có vẻ ổn trừ khi bằng cách nào đó nó được sử dụng đồng thời bởi nhiều lệnh gọi bên trong bộ điều khiển. Trong một chủ đề về chủ đề này, ScottGu nói:

Bộ điều khiển chỉ tồn tại cho một yêu cầu duy nhất - vì vậy khi kết thúc xử lý một yêu cầu, chúng sẽ được thu thập (có nghĩa là DataContext được thu thập) ...

Vì vậy, dù sao, điều đó có thể không phải là nó, nhưng một lần nữa nó có lẽ đáng để thử, có lẽ kết hợp với một số thử nghiệm tải.


3

Q. Tại sao bạn lại lưu trữ AnswerCounttrong Postsbảng ngay từ đầu?

Một cách tiếp cận thay thế là loại bỏ "ghi lại" vào Postsbảng bằng cách không lưu trữ AnswerCounttrong bảng mà tính toán động số câu trả lời cho bài đăng theo yêu cầu.

Có, điều này có nghĩa là bạn đang chạy một truy vấn bổ sung:

SELECT COUNT(*) FROM Answers WHERE post_id = @id

hoặc thông thường hơn (nếu bạn đang hiển thị cái này cho trang chủ):

SELECT p.post_id, 
     p.<additional post fields>,
     a.AnswerCount
FROM Posts p
    INNER JOIN AnswersCount_view a
    ON <join criteria>
WHERE <home page criteria>

nhưng điều này thường dẫn đến INDEX SCANvà có thể hiệu quả hơn trong việc sử dụng tài nguyên hơn là sử dụng READ ISOLATION.

Có nhiều cách để lột da mèo. Việc hủy chuẩn hóa sơ bộ một lược đồ cơ sở dữ liệu có thể gây ra các vấn đề về khả năng mở rộng.


3

Bạn chắc chắn muốn READ_COMMITTED_SNAPSHOT được đặt thành bật, điều này không phải là theo mặc định. Điều đó cung cấp cho bạn ngữ nghĩa MVCC. Nó giống như thứ mà Oracle sử dụng theo mặc định. Có một cơ sở dữ liệu MVCC cực kỳ hữu ích, KHÔNG sử dụng một cơ sở dữ liệu là điều điên rồ. Điều này cho phép bạn chạy những điều sau bên trong một giao dịch:

Cập nhật NGƯỜI DÙNG Đặt FirstName = 'foobar'; // quyết định ngủ nướng trong một năm.

trong khi đó mà không phạm những điều trên, mọi người có thể tiếp tục chọn từ bảng đó. Nếu bạn không quen thuộc với MVCC, bạn sẽ bị sốc rằng bạn đã từng có thể sống mà không có nó. Nghiêm túc.


3

Đặt mặc định của bạn để đọc không cam kết không phải là một ý kiến ​​hay. Không nghi ngờ gì nữa, ý chí của bạn đưa ra những mâu thuẫn và kết thúc bằng một vấn đề tồi tệ hơn những gì bạn có bây giờ. Tính năng cô lập ảnh chụp nhanh có thể hoạt động tốt, nhưng đó là một sự thay đổi mạnh mẽ đối với cách thức hoạt động của Máy chủ Sql và đặt một tải rất lớn lên tempdb.

Đây là những gì bạn nên làm: sử dụng try-catch (trong T-SQL) để phát hiện tình trạng deadlock. Khi nó xảy ra, chỉ cần chạy lại truy vấn. Đây là thực hành lập trình cơ sở dữ liệu tiêu chuẩn.

Có những ví dụ điển hình về kỹ thuật này trong Kinh thánh Sql Server 2005 của Paul Nielson .

Đây là một mẫu nhanh mà tôi sử dụng:

-- Deadlock retry template

declare @lastError int;
declare @numErrors int;

set @numErrors = 0;

LockTimeoutRetry:

begin try;

-- The query goes here

return; -- this is the normal end of the procedure

end try begin catch
    set @lastError=@@error
    if @lastError = 1222 or @lastError = 1205 -- Lock timeout or deadlock
    begin;
        if @numErrors >= 3 -- We hit the retry limit
        begin;
            raiserror('Could not get a lock after 3 attempts', 16, 1);
            return -100;
        end;

        -- Wait and then try the transaction again
        waitfor delay '00:00:00.25';
        set @numErrors = @numErrors + 1;
        goto LockTimeoutRetry;

    end;

    -- Some other error occurred
    declare @errorMessage nvarchar(4000), @errorSeverity int
    select    @errorMessage = error_message(),
            @errorSeverity = error_severity()

    raiserror(@errorMessage, @errorSeverity, 1)

    return -100
end catch;    

2
tại sao giải pháp này làm cho tôi co rúm người? !! tôi sẽ xem xét TẠI SAO lại có một bế tắc .. không phải là một ban nhạc thực sự nghèo đã hỗ trợ cho vấn đề này.
Pure.Krome

2

Một điều đã làm cho tôi trong quá khứ là đảm bảo tất cả các truy vấn và cập nhật của tôi đều truy cập tài nguyên (bảng) theo cùng một thứ tự.

Có nghĩa là, nếu một truy vấn cập nhật theo thứ tự Table1, Table2 và một truy vấn khác cập nhật nó theo thứ tự Table2, Table1 thì bạn có thể thấy bế tắc.

Không chắc liệu bạn có thể thay đổi thứ tự cập nhật vì bạn đang sử dụng LINQ hay không. Nhưng nó là một cái gì đó để xem xét.


1

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?

Một vài giây chắc chắn sẽ được chấp nhận. Có vẻ như nó sẽ không dài đến vậy, trừ khi có một số lượng lớn người gửi câu trả lời cùng một lúc.


1

Tôi đồng ý với Jeremy về điều này. Bạn hỏi liệu bạn có nên tạo bối cảnh dữ liệu mới cho mỗi bộ điều khiển hay mỗi trang hay không - Tôi có xu hướng tạo một bối cảnh mới cho mọi truy vấn độc lập.

Hiện tại, tôi đang xây dựng một giải pháp được sử dụng để triển khai ngữ cảnh tĩnh như bạn làm và khi tôi ném hàng tấn yêu cầu vào con quái vật của máy chủ (triệu +) trong các bài kiểm tra căng thẳng, tôi cũng nhận được các khóa đọc / ghi ngẫu nhiên.

Ngay sau khi tôi thay đổi chiến lược của mình để sử dụng ngữ cảnh dữ liệu khác ở cấp LINQ cho mỗi truy vấn và tin tưởng rằng máy chủ SQL có thể hoạt động phép thuật tổng hợp kết nối của nó, các khóa dường như biến mất.

Tất nhiên, tôi phải chịu một số áp lực về thời gian, vì vậy hãy thử nhiều thứ trong cùng một thời gian, vì vậy tôi không thể chắc chắn 100% đó là điều đã khắc phục được nó, nhưng tôi có một sự tự tin cao - hãy nói theo cách .


1

Bạn nên thực hiện đọc bẩn.

SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

Nếu bạn không hoàn toàn yêu cầu tính toàn vẹn của giao dịch hoàn hảo với các truy vấn của mình, bạn nên sử dụng các phép đọc bẩn khi truy cập các bảng có tính đồng thời cao. Tôi cho rằng bảng Bài đăng của bạn sẽ là một trong số đó.

Điều này có thể cung cấp cho bạn cái gọi là "lần đọc ảo", đó là khi truy vấn của bạn hoạt động dựa trên dữ liệu từ một giao dịch chưa được cam kết.

Chúng tôi không chạy 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

Sử dụng các bài đọc bẩn. Bạn nói đúng ở chỗ chúng sẽ không cung cấp cho bạn độ chính xác hoàn hảo, nhưng chúng sẽ giải quyết các vấn đề về khóa chết của bạn.

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ệ

Nếu bạn triển khai các lần đọc bẩn trên "ngữ cảnh cơ sở dữ liệu cơ sở", bạn luôn có thể kết hợp các cuộc gọi riêng lẻ của mình bằng cách sử dụng mức cách ly cao hơn nếu bạn cần tính toàn vẹn của giao dịch.


1

Vậy có vấn đề gì với việc thực hiện cơ chế thử lại? Sẽ luôn có khả năng xảy ra bế tắc, vậy tại sao không có một số logic để xác định nó và chỉ cần thử lại?

Ít nhất một số tùy chọn khác sẽ không đưa ra các hình phạt về hiệu suất được áp dụng mọi lúc khi hệ thống thử lại hiếm khi xảy ra?

Ngoài ra, đừng quên một số loại ghi nhật ký khi thử lại xảy ra để bạn không rơi vào tình huống hiếm khi trở nên thường xuyên.


1

Bây giờ tôi thấy câu trả lời của Jeremy, tôi nghĩ rằng tôi nhớ mình đã nghe nói rằng cách tốt nhất là sử dụng DataContext mới cho mỗi thao tác dữ liệu. Rob C Văn phòng phẩm đã viết một số bài về DataContext, và anh ấy luôn cập nhật chúng thay vì sử dụng một bài.

Đây là mẫu mà chúng tôi đã sử dụng cho Video.Show ( liên kết đến chế độ xem nguồn trong CodePlex ):

using System.Configuration;
namespace VideoShow.Data
{
  public class DataContextFactory
  {
    public static VideoShowDataContext DataContext()
    {
        return new VideoShowDataContext(ConfigurationManager.ConnectionStrings["VideoShowConnectionString"].ConnectionString);
    }
    public static VideoShowDataContext DataContext(string connectionString)
    {
        return new VideoShowDataContext(connectionString);
    }
  }
}

Sau đó, ở cấp dịch vụ (hoặc thậm chí chi tiết hơn, để cập nhật):

private VideoShowDataContext dataContext = DataContextFactory.DataContext();

public VideoSearchResult GetVideos(int pageSize, int pageNumber, string sortType)
{
  var videos =
  from video in DataContext.Videos
  where video.StatusId == (int)VideoServices.VideoStatus.Complete
  orderby video.DatePublished descending
  select video;
  return GetSearchResult(videos, pageSize, pageNumber);
}

0

Tôi sẽ phải đồng ý với Greg miễn là đặt mức cô lập để đọc không cam kết không có bất kỳ ảnh hưởng xấu nào đến các truy vấn khác.

Tôi muốn biết, Jeff, việc đặt nó ở cấp cơ sở dữ liệu sẽ ảnh hưởng như thế nào đến một truy vấn như sau:

Begin Tran
Insert into Table (Columns) Values (Values)
Select Max(ID) From Table
Commit Tran

0

Tôi không sao cả nếu hồ sơ của tôi lỗi thời vài phút.

Bạn đang thử đọc lại sau khi không thành công? Chắc chắn có thể xảy ra khi kích hoạt hàng tấn lần đọc ngẫu nhiên mà một số ít sẽ đạt được khi họ không thể đọc. Hầu hết các ứng dụng mà tôi làm việc đều có rất ít lần ghi so với số lần đọc và tôi chắc chắn rằng số lần đọc không ở đâu gần con số bạn đang nhận.

Nếu việc triển khai "READ UNCOMMITTED" không giải quyết được vấn đề của bạn, thì thật khó để trợ giúp mà không cần biết thêm nhiều về cách xử lý. Có thể có một số tùy chọn điều chỉnh khác có thể giúp ích cho hành vi này. Trừ khi một số chuyên gia về MSSQL đến giải cứu, tôi khuyên bạn nên gửi vấn đề cho nhà cung cấp.


0

Tôi sẽ tiếp tục điều chỉnh mọi thứ; hệ thống con đĩa hoạt động như thế nào? Độ dài hàng đợi đĩa trung bình là bao nhiêu? Nếu I / O đang sao lưu, vấn đề thực sự có thể không phải là hai truy vấn này đang bị khóa, mà có thể là một truy vấn khác đang làm tắc nghẽn hệ thống; bạn đã đề cập đến một truy vấn mất 20 giây đã được điều chỉnh, còn những truy vấn khác không?

Tập trung vào việc rút ngắn các truy vấn dài dòng, tôi cá rằng các vấn đề bế tắc sẽ biến mất.


0

Gặp phải vấn đề tương tự và không thể sử dụng "IsolationLevel = IsolationLevel.ReadUncomished" trên TransactionScope vì máy chủ không bật DTS (!).

Đó là những gì tôi đã làm với một phương thức mở rộng:

public static void SetNoLock(this MyDataContext myDS)
{
    myDS.ExecuteCommand("SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED");
}

Vì vậy, đối với những lựa chọn sử dụng bảng đồng thời quan trọng, chúng tôi bật "khóa" như sau:

using (MyDataContext myDS = new MyDataContext())
{
   myDS.SetNoLock();

   //  var query = from ...my dirty querys here...
}

Sugestions được chào đón!

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.