Đọc một hàng cập nhật một phần?


15

Giả sử tôi có hai truy vấn, chạy trong hai phiên riêng biệt trong SSMS:

Phần đầu tiên:

UPDATE Person
SET Name='Jonny', Surname='Cage'
WHERE Id=42

Phiên họp thứ hai:

SELECT Name, Surname
FROM Person WITH(NOLOCK)
WHERE Id > 30

Có thể là SELECTcâu lệnh có thể đọc một hàng được cập nhật một nửa, ví dụ một hàng có Name = 'Jonny'Surname = 'Goody'?

Các truy vấn được thực hiện gần như đồng thời trong các phiên riêng biệt.

Câu trả lời:


22

Có, trong một số trường hợp, SQL Server có thể đọc giá trị của một cột từ phiên bản "cũ" của hàng và giá trị của một cột khác từ phiên bản "mới" của hàng.

Thiết lập:

CREATE TABLE Person
  (
     Id      INT PRIMARY KEY,
     Name    VARCHAR(100),
     Surname VARCHAR(100)
  );

CREATE INDEX ix_Name
  ON Person(Name);

CREATE INDEX ix_Surname
  ON Person(Surname);

INSERT INTO Person
SELECT TOP 1000000 ROW_NUMBER() OVER (ORDER BY @@SPID),
                   'Jonny1',
                   'Jonny1'
FROM   master..spt_values v1,
       master..spt_values v2 

Trong kết nối đầu tiên, chạy này:

WHILE ( 1 = 1 )
  BEGIN
      UPDATE Person
      SET    Name = 'Jonny2',
             Surname = 'Jonny2'

      UPDATE Person
      SET    Name = 'Jonny1',
             Surname = 'Jonny1'
  END 

Trong kết nối thứ hai, chạy này:

DECLARE @Person TABLE (
  Id      INT PRIMARY KEY,
  Name    VARCHAR(100),
  Surname VARCHAR(100));

SELECT 'Setting intial Rowcount'
WHERE  1 = 0

WHILE @@ROWCOUNT = 0
  INSERT INTO @Person
  SELECT Id,
         Name,
         Surname
  FROM   Person WITH(NOLOCK, INDEX = ix_Name, INDEX = ix_Surname)
  WHERE  Id > 30
         AND Name <> Surname

SELECT *
FROM   @Person 

Sau khi chạy khoảng 30 giây tôi nhận được:

nhập mô tả hình ảnh ở đây

Các SELECTtruy vấn được lấy các cột từ các chỉ số clustered không chứ không phải là nhóm chỉ số (mặc dù do sự gợi ý).

nhập mô tả hình ảnh ở đây

Tuyên bố cập nhật nhận được một kế hoạch cập nhật rộng ...

nhập mô tả hình ảnh ở đây

... và cập nhật các chỉ mục theo trình tự để có thể đọc các giá trị "trước" từ một chỉ mục và "sau" từ chỉ mục kia.

Cũng có thể truy xuất hai phiên bản khác nhau của cùng một giá trị cột.

Trong kết nối đầu tiên, chạy này:

DECLARE @A VARCHAR(MAX) = 'A';
DECLARE @B VARCHAR(MAX) = 'B';

SELECT @A = REPLICATE(@A, 200000),
       @B = REPLICATE(@B, 200000);

CREATE TABLE T
  (
     V VARCHAR(MAX) NULL
  );

INSERT INTO T
VALUES     (@B);

WHILE 1 = 1
  BEGIN
      UPDATE T
      SET    V = @A;

      UPDATE T
      SET    V = @B;
  END   

Và sau đó trong lần thứ hai, chạy này:

SELECT 'Setting intial Rowcount'
WHERE  1 = 0;

WHILE @@ROWCOUNT = 0
  SELECT LEFT(V, 10)  AS Left10,
         RIGHT(V, 10) AS Right10
  FROM   T WITH (NOLOCK)
  WHERE  LEFT(V, 10) <> RIGHT(V, 10);

DROP TABLE T;

Ngay lập tức, điều này trả lại kết quả sau cho tôi

+------------+------------+
|   Left10   |  Right10   |
+------------+------------+
| BBBBBBBBBB | AAAAAAAAAA |
+------------+------------+

1
Tôi có đúng không nếu tôi có một bảng TẠO TABLE Person (Id INT PRIMARY KEY, Name VARCHAR (100), Surname VARCHAR (100)) (không có bất kỳ chỉ mục nào về Tên và Họ) và hai truy vấn như trong câu hỏi, được thực thi trong các phiên riêng biệt, sau đó tôi sẽ nhận được một hàng cập nhật hoặc một hàng cũ, nhưng không phải là kết quả trung gian của việc cập nhật hàng?
Tesh

@Tesh vâng Tôi không nghĩ có thể nhận được bất kỳ kết quả nào khác vì tất cả sẽ nằm trên cùng một trang và được bảo vệ bởi một chốt trong quá trình viết.
Martin Smith

Bất cứ điều gì bất ngờ bạn nhận được với một WITH (NLOCK)gợi ý là lỗi của riêng bạn. Điều này có thể xảy ra mà không có một NOLOCKgợi ý?
Ross Presser

2
@RossPresser - Có với ví dụ đầu tiên, xem phần giao điểm chỉ mục ở đây blog.msdn.com/b/craigfr/archive/2007/05/02/ . Lần thứ hai tôi đoán có khả năng nó có thể nếu có hai phiên bản cam kết khác nhau. Không chắc chắn nó sẽ có thể kỹ sư trong thực 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.