Kısmen güncellenmiş bir satır mı okudunuz?


15

SSMS'de iki ayrı oturumda çalışan iki sorgum olduğunu varsayalım:

İlk oturum:

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

İkinci oturum:

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

İfadenin SELECTyarı güncellenmiş bir satırı, örneğin Name = 'Jonny've ile birini okuyabilmesi mümkün müdür Surname = 'Goody'?

Sorgular neredeyse aynı anda ayrı oturumlarda yürütülür.

Yanıtlar:


22

Evet, SQL Server bazı durumlarda satırın "eski" sürümünden bir sütunun değerini ve satırın "yeni" sürümünden başka bir sütunun değerini okuyabilir.

Kurmak:

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 

İlk bağlantıda şunu çalıştırın:

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

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

İkinci bağlantıda şunu çalıştırın:

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 

Yaklaşık 30 saniye koştuktan sonra şunu elde ederim:

resim açıklamasını buraya girin

SELECTSorgu olmayan kümelenmiş endeksler yerine (ipuçları nedeniyle de olsa) kümelenmiş dizin sütunları alınırken edilir.

resim açıklamasını buraya girin

Güncelleme bildirimi geniş bir güncelleme planı alır ...

resim açıklamasını buraya girin

... ve dizinleri sırayla günceller, böylece bir dizinden "önce" ve diğerinden "sonra" değerleri okunabilir.

Aynı sütun değerinin iki farklı versiyonunu almak da mümkündür.

İlk bağlantıda şunu çalıştırın:

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   

Ve sonra ikincisinde şunu çalıştırın:

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;

Hemen, bu benim için aşağıdaki sonucu döndürdü

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

1
Ben bir tablo CREATE TABLE Kişi (Id INT PRIMARY KEY, Name VARCHAR (100), Soyadı VARCHAR (100)) (Ad ve Soyadı üzerinde herhangi bir dizin olmadan) ve yürütülen soru gibi iki sorguya sahip olduğumda haklı mıyım ayrı oturumlarda, o zaman güncellenmiş bir satır veya eski bir satır alırsınız, ancak satır güncelleme bazı ara sonucu değil?
Tesh

@ Evet evet Ben aynı sayfada olacak ve yazma sırasında bir mandal ile korunur gibi başka bir sonuç almak mümkün olacağını sanmıyorum.
Martin Smith

Bir WITH (NLOCK)ipucu ile beklenmedik bir şey sizin kendi hatanızdır. Bu bir NOLOCKipucu olmadan olabilir mi?
Ross Presser

2
@RossPresser - İlk örneğe evet, buradaki dizin kesişim parçasına bakın blogs.msdn.com/b/craigfr/archive/2007/05/02/… . İkincisi için, potansiyel olarak iki farklı taahhütlü versiyon mevcut olabilir. Uygulamada mühendis olmanın mümkün olacağından emin değilim.
Martin Smith
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.