2008-09-11 30 views
13

Điều này sẽ giải thích một chút. Những gì tôi đã làm là tạo ra một hàng đợi thông báo tùy chỉnh cụ thể trong SQL Server 2005. Tôi có một bảng với các thông điệp có chứa dấu thời gian cho cả sự thừa nhận và hoàn thành. Các thủ tục lưu trữ mà người gọi thực hiện để có được thông báo tiếp theo trong hàng đợi của họ cũng thừa nhận thông báo. Càng xa càng tốt. Vâng, nếu hệ thống đang trải qua một số lượng lớn các giao dịch (hàng ngàn mỗi phút), không phải là nó có thể cho một thông điệp được thừa nhận bởi một thực hiện các thủ tục được lưu trữ trong khi khác được chuẩn bị để chính nó? Hãy để tôi giúp bằng cách hiển thị mã SQL của tôi trong proc lưu trữ:Làm thế nào để bạn khóa bảng trong SQL Server 2005, và tôi thậm chí nên làm điều đó?

--Grab the next message id 
declare @MessageId uniqueidentifier 
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands); 

--Acknowledge the message 
update ActionMessages 
set AcknowledgedTime = getdate() 
where ActionMessageId = @MessageId 

--Select the entire message 
... 
... 

Trong đoạn mã trên, không thể khác stored procedure chạy cùng một lúc có được cùng một id và cố gắng để thừa nhận nó cùng một lúc? Tôi có thể (hoặc tôi nên) thực hiện một số loại khóa để ngăn chặn một proc được lưu trữ từ thừa nhận thông báo rằng proc lưu trữ khác là truy vấn?

Chà, điều này có ý nghĩa gì không? Hơi khó để đặt vào các từ ...

+0

bạn có thể muốn gắn thẻ lại để thay đổi "tốt nhất" thành "thực hành tốt nhất" thường được sử dụng hơn – martinatime

Trả lời

7

Something như thế này

--Grab the next message id 
begin tran 
declare @MessageId uniqueidentifier 
select top 1 @MessageId = ActionMessageId from UnacknowledgedDemands with(holdlock, updlock); 

--Acknowledge the message 
update ActionMessages 
set AcknowledgedTime = getdate() 
where ActionMessageId = @MessageId 

-- some error checking 
commit tran 

--Select the entire message 
... 
... 
-1

Bạn muốn quấn mã của mình trong một giao dịch, khi đó máy chủ SQL sẽ xử lý khóa các hàng hoặc bảng thích hợp.

begin transaction 

--Grab the next message id 
declare @MessageId uniqueidentifier 
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands); 

--Acknowledge the message 
update ActionMessages 
set AcknowledgedTime = getdate() 
where ActionMessageId = @MessageId 

commit transaction 

--Select the entire message 
... 
+0

Nó có đơn giản không ... liệu khóa (được chia sẻ) có được giữ bởi câu lệnh đầu tiên hay không trên mức cô lập giao dịch và trường hợp tốt nhất (nếu mức cách ly là như vậy mà khóa chia sẻ được giữ), thì mã đó sẽ dẫn đến deadlocks khi hai kết nối khác nhau nhận được cùng một thông báo và cả hai cố gắng cập nhật nó (mỗi ngăn chặn từ làm như vậy bằng khóa của người khác). – Tao

0

Nếu bạn thực sự đang xử lý từng thứ một? Không nên bạn chỉ có SQL Server thừa nhận tất cả các tin nhắn chưa được trả lời với ngày hôm nay và trả lại chúng? (Tất cả cũng trong một giao dịch dĩ nhiên)

+0

Không phải là những gì tôi đang làm? SQL Server đang thừa nhận các thông báo thay mặt cho người gọi và trả lại chúng. – Kilhoffer

+0

Không, tôi có ý nghĩa như thế này (chưa được kiểm tra): BEGIN GIAO DỊCH SELECT * FROM UnacknowledgedDemands; ActionMessages CẬP NHẬT SET AcknowledgetTime = getdate() nơi có (SELECT * FROM UnacknowledgedDemands ĐÂU ActionMessages.ActionMessageId = UnacknowledgedDemands.ActionMessageId) COMMIT GIAO DỊCH – rpetrich

1

@Kilhoffer:

Toàn bộ hàng loạt SQL được phân tách trước khi thực hiện, vì vậy SQL biết rằng bạn đang đi để làm một bản cập nhật để bàn cũng như chọn từ nó .

Chỉnh sửa: Ngoài ra, SQL sẽ không nhất thiết phải khóa toàn bộ bảng - nó chỉ có thể khóa các hàng cần thiết. Xem here để biết tổng quan về khóa trong máy chủ SQL.

+0

Tôi không đồng ý với điều đó. Phân tích cú pháp không liên quan gì đến nó. Nếu nó đã làm, SQL chạy qua EXECUTE sẽ không được giao dịch an toàn. –

+0

Nhưng không có EXECUTE ở đây. Mặc dù vậy, làm thế nào để SQL biết phải khóa những gì khi chạy SQL tùy ý thông qua thực thi? – Blorgbeard

+0

Máy chủ SQL quyết định những gì cần khóa và có giữ khóa hoặc giải phóng chúng hay không, vì nó xảy ra (vì nó chạy mỗi câu lệnh trong giao dịch), KHÔNG phải lúc phân tích cú pháp. Do đó không có sự khác biệt giữa các cuộc gọi EXEC và một lô bình thường. Sự khác biệt duy nhất sẽ là trong việc lựa chọn kế hoạch truy vấn (cho dù sử dụng một bộ nhớ đệm hay không). – Tao

0

Đọc thêm về SQL Server Chọn Khóa herehere. SQL Server có khả năng gọi một khóa bảng trên một lựa chọn. Sẽ không có gì xảy ra với bảng trong giao dịch. Khi giao dịch hoàn tất, mọi lần chèn hoặc cập nhật sẽ tự giải quyết.

+1

Vì vậy, điều này có nghĩa là chỉ cần gói mã trên vào một giao dịch, SQL Server thực tế thực hiện việc chọn khóa như được mô tả trong các liên kết ở trên? – Kilhoffer

1

Thay vì khóa rõ ràng, thường leo thang bởi SQL Server để granularity cao hơn mong muốn, tại sao không chỉ cố gắng tiếp cận này:

declare @MessageId uniqueidentifier 
select top 1 @MessageId = ActionMessageId from UnacknowledgedDemands 

update ActionMessages 
    set AcknowledgedTime = getdate() 
    where ActionMessageId = @MessageId and AcknowledgedTime is null 

if @@rowcount > 0 
    /* acknoweldge succeeded */ 
else 
    /* concurrent query acknowledged message before us, 
    go back and try another one */ 

Càng ít bạn khóa - các đồng thời cao hơn mà bạn có.

2

Điều này có vẻ giống như các loại tình huống mà OUTPUT có thể hữu ích:

-- Acknowledge and grab the next message 
declare @message table (
    -- ...your `ActionMessages` columns here... 
) 
update ActionMessages 
set AcknowledgedTime = getdate() 
output INSERTED.* into @message 
where ActionMessageId in (select top(1) ActionMessageId from UnacknowledgedDemands) 
    and AcknowledgedTime is null 

-- Use the data in @message, which will have zero or one rows assuming 
-- `ActionMessageId` uniquely identifies a row (strongly implied in your question) 
... 
... 

Tại đây, chúng tôi cập nhật và lấy hàng trong hoạt động tương tự, mà nói với tôi ưu truy vấn chính xác những gì chúng tôi đang làm , cho phép nó chọn khóa chi tiết nhất có thể và duy trì nó trong thời gian ngắn nhất có thể. (Mặc dù tiền tố cột là INSERTED, OUTPUT cũng giống như các trình kích hoạt, được biểu thị dưới dạng số UPDATE giống như xóa hàng và chèn hàng mới.)

tôi cần thêm thông tin về ActionMessagesUnacknowledgedDemands bạn bảng (views/TVFs/bất cứ điều gì), chưa kể đến một sự hiểu biết lớn hơn của khóa tự động SQL Server, để nói cho dù đó and AcknowledgedTime is null khoản là cần thiết. Nó có để bảo vệ chống lại một điều kiện chủng tộc giữa các lựa chọn phụ và cập nhật. Tôi chắc chắn sẽ không cần thiết nếu chúng tôi đã chọn từ chính bản thân số ActionMessages (ví dụ: where AcknowledgedTime is null với số top trên số update, thay vì chọn phụ trên UnacknowledgedDemands). Tôi mong đợi ngay cả khi nó không cần thiết, nó vô hại.

Lưu ý rằng OUTPUT nằm trong SQL Server 2005 trở lên. Đó là những gì bạn nói bạn đang sử dụng, nhưng nếu khả năng tương thích với cài đặt SQL Server 2000 geriatric được yêu cầu, bạn muốn đi theo một cách khác.

+0

(Khá muộn cho bữa tiệc, nhưng tôi thấy không ai đề cập đến nó, vì vậy ...) –

Các vấn đề liên quan