2010-01-25 33 views
8

Tôi cần phải chọn đầu tiên (giả sử) 10.000 hàng trong cơ sở dữ liệu và trả lại chúng. Có thể có nhiều khách hàng thực hiện thao tác này cùng một lúc. Tôi đã đưa ra truy vấn này:Bản cập nhật có hoạt động nguyên tử được chọn lồng nhau không?

update v set v.batch_Id = :batchId 
    from tblRedir v 
    inner join (
     select top 10000 id 
      from tblRedir 
      where batch_Id is null 
      order by Date asc 
    ) v2 on v.id=v2.id 

Đây là một hoạt động bao gồm cập nhật và chọn lồng nhau. Cả hai truy vấn đều hoạt động trên cùng một bảng (tblRedir). Ý tưởng là các hàng được đầu tiên đánh dấu bằng một Id lô độc đáo và sau đó trở về qua

select * from tblRedir where batch_id = :batchId 

(các Id lô là một định danh duy nhất (ví dụ như dấu thời gian hoặc guid) cho mỗi lần cập nhật này)

Câu hỏi của tôi:

Tôi nghĩ rằng hoạt động cập nhật với lựa chọn lồng nhau là nguyên tử - điều đó có nghĩa là mọi khách hàng đều nhận được bộ dữ liệu riêng của mình là duy nhất (không có khách hàng nào khác nhận được tập con dữ liệu của anh ấy).

Tuy nhiên có vẻ rằng tôi sai - trong một số trường hợp có những khách hàng mà không nhận được dữ liệu, vì lẽ họ lần đầu tiên cả thực hiện lựa chọn và sau đó cả hai thực hiện cập nhật (vì vậy khách hàng đầu tiên không có đánh dấu hàng).

Hoạt động này có phải là nguyên tử hay không?


tôi làm việc với SQL Server 2005. Các truy vấn được chạy qua NHibernate như thế này

session.CreateSQLQuery('update....') 

Trả lời

5

SELECT nơi ổ khóa được chia sẻ trên các hàng đọc mà sau đó có thể được dỡ bỏ trong READ COMMITED chế độ cách ly.

UPDATE đặt khóa cập nhật sau đó được quảng bá cho khóa độc quyền. Chúng không được dỡ bỏ cho đến khi kết thúc giao dịch.

Bạn nên thực hiện khóa để giữ lại ngay sau khi được đặt.

Bạn có thể thực hiện điều này bằng cách thực hiện mức cách ly giao dịch REPEATABLE READ sẽ giữ lại khóa được chia sẻ cho đến khi kết thúc giao dịch và ngăn chặn UPDATE một phần khỏi việc khóa các hàng này.

Ngoài ra, bạn có thể viết lại truy vấn của bạn như thế này:

WITH q AS 
     (
     SELECT TOP 10000 * 
     FROM mytable WITH (ROWLOCK, READPAST) 
     WHERE batch_id IS NULL 
     ORDER BY 
       date 
     ) 
UPDATE q 
SET  batch_id = @myid 

, mà chỉ sẽ bỏ qua các hàng bị khóa.

+0

Thx cho câu trả lời của bạn. Tôi đã thử các thay thế ('với q là ...') và có vẻ như là READPAST không thể được sử dụng với HOLDLOCK. Tôi đã thử mức cách ly 'đọc cam kết', 'đọc lặp lại' và trong cả hai trường hợp máy chủ sql phàn nàn 'Bạn chỉ có thể chỉ định khóa READPAST trong các cấp độ READ READITTED hoặc REPEATABLE READ. Truy vấn có đúng ngay cả khi không có HOLDLOCK không? – stej

+0

'@ stej': Tôi không nghĩ rằng' SQL Server' sẽ chia 'SELECT' và' UPDATE' phần trong trường hợp này, vì vậy có, các khóa cập nhật sẽ được đặt tự động. Bạn có thể xóa 'HOLDLOCK'. – Quassnoi

+0

Cảm ơn bạn. Tôi đã thử nó, có vẻ như nó hoạt động. Trong một số trường hợp có nhiều bế tắc, nhưng đột nhiên không có gì - thật khó để tái tạo nó.Trong trường hợp tôi sẽ có thể mô tả nó bằng cách nào đó, tôi sẽ gửi một câu hỏi mới. – stej

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