Can I rely on reading SQL Server Identity values in order?


24

TL; DR: Aşağıdaki soru aşağı doğru kayıyor: Bir satır eklerken , bir dış gözlemcinin daha yeni görebileceği kümelenmiş dizindeki yeni bir değerin üretilmesi ve karşılık gelen satır anahtarının kilitlenmesi arasında bir fırsat penceresi var mı? eşzamanlı bir işlem tarafından eklenen değer? (SQL Server'da.)Identity Identity

Detaylı versiyon

Tablonun kümelenmiş indeksinin anahtarı olan (ayrıca birkaç kümelenmemiş ek dizini olan) bir Identitysütunu olan bir SQL Server masam var CheckpointSequence. Satırlar tabloya birkaç eşzamanlı işlem ve iş parçacığı (izolasyon düzeyinde ve olmadan ) eklenir . Aynı zamanda, kümelenmiş dizinden, o sütuna göre sıralanan (aynı zamanda izolasyon düzeyinde , seçenek kapatılmış olarak) satırları düzenli olarak okuyan işlemler vardır .READ COMMITTEDIDENTITY_INSERTCheckpointSequenceREAD COMMITTEDREAD COMMITTED SNAPSHOT

Şu anda okuma işlemlerinin bir kontrol noktasını asla atlayamayacağı gerçeğine güveniyorum. Sorum şu: Bu mülke güvenebilir miyim? Olmazsa doğrulamak için ne yapabilirim?

Örnek: kimlik değerlerinin olan satırlar 1, 2, 3, 4, ve 5 sokulur, okuyucu zaman olmamalıdır , önceki değerine sahip bir görme değerin 5 ile satır bkz 4. testler gösteriyor ki, bir içeren bir sorgu, ORDER BY CheckpointSequencemadde ( ve bir WHERE CheckpointSequence > -1cümle), 4. satırın ne zaman okunacağını, ancak henüz 5. satırın daha önce gerçekleştirilmiş olmasına rağmen henüz taahhüt edilmediğini güvenilir bir şekilde engeller.

En azından teoride, bu varsayımın bozulmasına neden olabilecek bir yarış durumu olabileceğine inanıyorum. Maalesef, belgelendirme birden fazla eşzamanlı işlem bağlamında Identitynasıl Identityçalıştığı hakkında pek fazla bir şey ifade etmiyor , sadece “Her yeni değer mevcut tohum ve artışa göre üretiliyor” diyor. ve "Belirli bir işlem için her yeni değer, tablodaki eşzamanlı diğer işlemlerden farklıdır." ( MSDN )

Benim akıl yürütme, bir şekilde bu şekilde çalışması gerekir:

  1. Bir işlem başlatıldı (açıkça veya dolaylı olarak).
  2. Bir kimlik değeri (X) üretilir.
  3. İlgili satır kilidi, kimlik değerine bağlı olarak kümelenmiş endekste alınır (kilit yükseltme başlamazsa, bu durumda tüm tablo kilitlenir).
  4. Satır eklenir.
  5. İşlem gerçekleştirilir (çok uzun zaman sonra), bu nedenle kilit tekrar kaldırılır.

Bence 2. ve 3. adımlar arasında, çok küçük bir pencere var.

  • eşzamanlı bir oturum sonraki kimlik değerini (X + 1) üretebilir ve kalan tüm adımları uygulayabilir,
  • Böylece bir okuyucunun X + 1 değerini okuması için tam olarak bu noktada gelmesi, X'in değerini kaybetmesi.

Tabii ki, bunun olasılığı son derece düşük görünüyor; ama yine de - olabilirdi. Veya olabilir mi?

(Bağlamla ilgileniyorsanız: Bu, NEventStore'un SQL Kalıcılık Motorunun bir uygulamasıdır. NEventStore, her olayın yeni, artan bir denetim noktası sıra numarası aldığı bir yalnızca salt okunur olay deposu uygular. Müşteriler, kontrol noktası tarafından sipariş edilen olay mağazasından olayları okurlar. Her türlü hesaplamaları yapabilmek için, X kontrol noktası olan bir olay işlendikten sonra, müşteriler sadece "yeni" olayları, yani X + 1 ve üstü kontrol noktası olan olayları göz önünde bulundururlar.Bu nedenle, olayların hiçbir zaman atlanmaması çok önemlidir. . onlar daha göz önünde asla gibi ben şu anda olmadığını belirlemek için çalışıyorum Identity. tabanlı kontrol noktası uygulaması bu gereksinimi karşılar Bunlar kullanılan tam SQL ifadeleri : Şema , Yazarlar sorgu ,Okuyucunun Sorgusu .)

Eğer haklıysam ve yukarıda açıklanan durum ortaya çıkarsa, her ikisi de tatmin edici olmayan, onlarla başa çıkmak için yalnızca iki seçenek görebilirim:

  • X'i görmeden önce X + 1 değerinde bir kontrol noktası sırası görünce, X + 1'i kapatın ve daha sonra tekrar deneyin. Bununla birlikte, Identityelbette boşluk üretebileceğinden (örneğin, işlem geri alındığında), X asla gelmeyebilir.
  • Yani, aynı yaklaşım, ancak n milisaniyeden sonra boşluğu kabul edin. Bununla birlikte, n'nin değerini kabul etmeliyim?

Daha iyi bir fikrin var mı?


Kimlik yerine Sıra kullanmayı denediniz mi? Kimlik ile, hangi ekin belirli bir kimlik değeri elde edeceğini güvenilir bir şekilde tahmin edebileceğinizi sanmıyorum, ancak bu, bir sekans kullanarak sorun olmamalıdır. Tabii ki bu işlerin şimdi nasıl yapılacağını değiştiriyor.
Antoine Hernandez,

@ SoleDBAGuy Sıra, yukarıda açıklanan yarış koşullarını daha da olası hale getirmez mi? Yeni bir Sıra değeri X üretiyorum (yukarıdaki 2. adımı değiştirerek), sonra bir satır ekleyin (3. ve 4. adımlar). 2 ile 3 arasında, bir başkasının bir sonraki Sıra değeri X + 1'i üretme olasılığı vardır ve bunu taahhüt eder ve bir okuyucuyu X sıra değerini X ile eklemeden önce X + 1 değerini okur.
Fabian Schmied

Yanıtlar:


26

Bir satır eklerken, harici bir gözlemcinin eşzamanlı bir işlem tarafından eklenen yeni bir Kimlik değerini görebildiği, yeni bir Kimlik değerinin üretilmesi ve kümelenmiş dizindeki karşılık gelen satır anahtarının kilitlenmesi arasında bir fırsat penceresi var mı?

Evet.

Kimlik değerlerinin tahsis içeren kullanıcı işlem bağımsızdır . Bu, işlem geri alınsa bile kimlik değerlerinin tüketilmesinin bir nedenidir. Artırma işleminin kendisi yolsuzluğun önlenmesi için bir mandalla korunmaktadır, ancak bu korumaların kapsamıdır.

Uygulamanızın özel koşullarında, kimlik tahsisi (bir çağrı CMEDSeqGen::GenerateNewValue), ekleme için kullanıcı işleminin aktif hale getirilmesinden önce yapılır (ve böylece herhangi bir kilit alınmadan önce).

Kimlik değerini artırıp tahsis ettikten hemen sonra bir parçayı dondurmama izin vermek için eklenmiş bir hata ayıklayıcıyla eşzamanlı olarak iki kesici uç çalıştırarak, aşağıdakileri gösteren bir senaryoyu yeniden oluşturabildim:

  1. 1. Oturum bir kimlik değeri aldı (3)
  2. 2. Oturumda bir kimlik değeri elde edildi (4)
  3. 2. Oturum ekini gerçekleştirir ve tamamlar (bu nedenle 4. satır tamamen görünür durumdadır)
  4. 1. Oturum ekini gerçekleştirir ve taahhüt eder (3. satır)

3. adımdan sonra, kilitleme okumasının onaylandığı satır_sayısı kullanan bir sorgu aşağıdakileri döndürdü:

Ekran görüntüsü

Uygulamanızda, bu, Kontrol Noktası ID 3'ün yanlış atlanmasıyla sonuçlanacaktır.

Hatalı olma penceresi nispeten küçük, ancak var. Takılı bir hata ayıklayıcısından daha gerçekçi bir senaryo vermek için: Bir yürütme sorgusu iş parçacığı zamanlayıcıyı yukarıdaki 1. adımdan sonra verebilir. Bu, ikinci iş parçacığının orijinal iş parçacığı eklemeye devam etmeden önce bir kimlik değeri tahsis etmesini, eklemek ve işlemek için izin verir.

Netlik açısından, tahsis edildikten sonra ve kullanılmadan önce kimlik değerini koruyan kilitler veya başka senkronizasyon nesneleri yoktur. Örneğin, yukarıdaki 1. adımdan sonra, eşzamanlı bir işlem IDENT_CURRENT, satırın tabloda görünmeden önceki haliyle (hatta tamamlanmamış) T-SQL işlevlerini kullanarak yeni kimlik değerini görebilir .

Temel olarak, kimlik değerleri etrafında belgelendiğinden daha fazla garanti yoktur :

  • Her yeni değer mevcut tohum ve artışa göre üretilir.
  • Belirli bir işlem için her yeni değer, tablodaki diğer eşzamanlı işlemlerden farklıdır.

Bu gerçekten öyle.

Eğer sıkı işlem FIFO işleme gereklidir, büyük olasılıkla başka seçeneğimiz yok fakat manuel seri hale getirmek için. Uygulamanın daha az gerekliliği varsa, daha fazla seçeneğiniz vardır. Bu konuda soru% 100 açık değildir. Bununla birlikte, Remus Rusanu'nun Tabloları Kuyruk Olarak Kullanma adlı makalesinde bazı yararlı bilgiler bulabilirsiniz .


7

Paul White'ın kesinlikle doğru cevap vermesi halinde geçici olarak "atlanan" kimlik satırları için bir olasılık var. İşte bu davayı kendiniz için yeniden oluşturmak için küçük bir kod parçası.

Bir veritabanı ve bir test tablosu oluşturun:

create database IdentityTest
go
use IdentityTest
go
create table dbo.IdentityTest (ID int identity, c1 char(10))
create clustered index CI_dbo_IdentityTest_ID on dbo.IdentityTest(ID)

Eşzamanlı ekler gerçekleştirin ve bu tablodaki C # konsol programında seçer:

using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Threading;

namespace IdentityTest
{
    class Program
    {
        static void Main(string[] args)
        {
            var insertThreads = new List<Thread>();
            var selectThreads = new List<Thread>();

            //start threads for infinite inserts
            for (var i = 0; i < 100; i++)
            {
                insertThreads.Add(new Thread(InfiniteInsert));
                insertThreads[i].Start();
            }

            //start threads for infinite selects
            for (var i = 0; i < 10; i++)
            {
                selectThreads.Add(new Thread(InfiniteSelectAndCheck));
                selectThreads[i].Start();
            }
        }

        private static void InfiniteSelectAndCheck()
        {
            //infinite loop
            while (true)
            {
                //read top 2 IDs
                var cmd = new SqlCommand("select top(2) ID from dbo.IdentityTest order by ID desc")
                {
                    Connection = new SqlConnection("Server=localhost;Database=IdentityTest;Integrated Security=SSPI;Application Name=IdentityTest")
                };

                try
                {
                    cmd.Connection.Open();
                    var dr = cmd.ExecuteReader();

                    //read first row
                    dr.Read();
                    var row1 = int.Parse(dr["ID"].ToString());

                    //read second row
                    dr.Read();
                    var row2 = int.Parse(dr["ID"].ToString());

                    //write line if row1 and row are not consecutive
                    if (row1 - 1 != row2)
                    {
                        Console.WriteLine("row1=" + row1 + ", row2=" + row2);
                    }
                }
                finally
                {
                    cmd.Connection.Close();
                }
            }
        }

        private static void InfiniteInsert()
        {
            //infinite loop
            while (true)
            {
                var cmd = new SqlCommand("insert into dbo.IdentityTest (c1) values('a')")
                {
                    Connection = new SqlConnection("Server=localhost;Database=IdentityTest;Integrated Security=SSPI;Application Name=IdentityTest")
                };

                try
                {
                    cmd.Connection.Open();
                    cmd.ExecuteNonQuery();
                }
                finally
                {
                    cmd.Connection.Close();
                }
            }
        }
    }
}

Bu konsol, okuma başlıklarından biri bir girişi "kaçırdığında" her durum için bir satır yazdırır.


1
Güzel kod, ancak yalnızca ardışık ID'leri kontrol edersiniz ( "// satır1 ve satır ardışık değilse satır yaz" ). Kodunuzun yazdıracağı boşluklar olabilir. Bu, bu boşlukların daha sonra doldurulacağı anlamına gelmez.
ypercubeᵀᴹ

1
Kod, IDENTITYboşlukların üretileceği (bir işlemi geri almak gibi) senaryoyu tetiklemediğinden , yazdırılan satırlar gerçekten "atlandı" değerleri gösterir (veya en azından makinemde çalıştırıp kontrol ettiğimde yaptılar). Çok güzel repro örneği!
Fabian Schmied

5

Kimliklerin ardışık olmasını beklememek en iyisidir çünkü boşluk bırakabilecek birçok senaryo vardır. Kimliği soyut bir sayı gibi düşünmek ve ona bir anlam ifade etmemek daha iyidir.

Temel olarak, INSERT işlemlerini geri alırsanız (veya açıkça satırları silerseniz) boşluklar ortaya çıkabilir ve IDENTITY_INSERT tablo özelliğini AÇIK olarak ayarlarsanız, kopyalar oluşabilir.

Aşağıdaki durumlarda boşluklar oluşabilir:

  1. Kayıtlar silindi.
  2. Yeni bir kayıt eklemeye çalışırken bir hata oluştu (geri alındı)
  3. Açık değere sahip bir güncelleme / ekleme (identity_insert seçeneği).
  4. Artımlı değer 1'den fazla.
  5. Bir işlem geri alır.

Bir sütundaki kimlik özelliği hiçbir zaman garanti etmedi:

• Teklik

• Bir işlem içindeki ardışık değerler. Değerlerin ardışık olması gerekiyorsa, işlem masada özel bir kilit kullanmalı veya SERIALIZABLE izolasyon seviyesini kullanmalıdır.

• Sunucu yeniden başlatıldıktan sonra ardışık değerler.

• Değerlerin tekrar kullanılması.

Bu nedenle kimlik değerlerini kullanamıyorsanız, geçerli bir değeri içeren ayrı bir tablo oluşturun ve uygulamanızla birlikte tablo ve sayı atamasına erişimi yönetin. Bunun performansı etkileme potansiyeli var.

https://msdn.microsoft.com/en-us/library/ms186775(v=sql.105).aspx
https://msdn.microsoft.com/en-us/library/ms186775(v=sql.110) .aspx


Boşlukların birincil sorunum olmadığını düşünüyorum - asıl sorunum değerlerin görünürlüğünü artırmak. (Örneğin, kimlik değeri 7, kimlik değeri 6
olandan

1
Kimlik değerlerinin aşağıdaki gibi işlem yaptığını gördüm: 1, 2, 5, 3, 4.
stacylaray

Elbette, bu kolayca tekrarlanabilir, örneğin Lennart'ın cevabındaki senaryoyu kullanarak. Mücadelede bulunduğum soru , bir cümleciği olan bir sorgu kullanırken bu küme sırasını gözlemleyebilmem olup olmadığıdır ORDER BY CheckpointSequence(kümelenmiş dizinin sırasıdır). Kimlik değerinin oluşturulmasının INSERT ifadesi tarafından alınan kilitlerle herhangi bir şekilde bağlantılı olup olmadığı ya da bunların birbiri ardına SQL Server tarafından gerçekleştirilen ilgisiz iki eylem olup olmadığı sorusuna katlandığını düşünüyorum.
Fabian Schmied

1
Sorgu nedir? Onaylanmış okuma kullanılması durumunda, örneğinize göre sırayla 1, 2, 3, 5 gösterilirdi, çünkü onaylandılar ve 4'ü, yani kirli okumalar yapmadı. Ayrıca, NEventStore ile ilgili açıklamanız “Bu nedenle, bir daha asla göz önüne alınmayacakları gibi, olayların asla atlanmaması çok önemlidir.”
stacylaray

Sorgu yukarıda verilmiştir ( gist.github.com/fschmied/47f716c32cb64b852f90 ) - sayfalanmış, ancak basit bir kaynama yapıyorSELECT ... FROM Commits WHERE CheckpointSequence > ... ORDER BY CheckpointSequence . Bu sorgunun kilitli 4 satırını okuyacağını sanmıyorum, yoksa? (Denemelerime göre, sorgu 4. satır için KEY kilidini almaya çalıştığında
engelleniyor

1

Sunucunun ağır yük altında kalması durumunda zaman zaman sorun yaratabileceği, sorunların daha da kötüleşebileceğinden şüpheliyim. İki işlemi göz önünde bulundurun:

  1. T1: T'ye ekleyin ... - 5'in yerleştirildiğini söyleyin
  2. T2: T'ye yerleştirin ... - 6 yerleştirilir
  3. T2: taahhüt
  4. Reader 6 görüyor, 5 değil
  5. T1: taahhüt

Yukarıdaki senaryoda, LAST_READ_ID'niz 6 olacak, bu yüzden 5 asla okunmayacak.


Testlerim bu senaryonun sorun olmadığını gösteriyor gibi görünüyor çünkü Reader (adım 4) değeri 5 ile satır okumayı denediğinde (T1 kilitlerini açana kadar) engelleyecektir.
Fabian Schmied

Haklı olabilirsiniz, SQL sunucudaki kilitleme mekanizmasını o kadar iyi bilmiyorum (bu yüzden cevabımdan şüpheleniyorum).
Lennart

Okuyucunun izolasyon seviyesine bağlıdır. Bu benim hem görmek, hem engellemek, ya da sadece 6 görmek.
Michael Green

0

Bu betiği çalıştırıyor:

BEGIN TRAN;
INSERT INTO dbo.Example DEFAULT VALUES;
COMMIT;

Aşağıda, Genişletilmiş Etkinlik oturumu tarafından alınmış olarak edinilmiş ve bırakılmış gördüğüm kilitler şunlardır:

name            timestamp                   associated_object_id    mode    object_id   resource_type   session_id  resource_description
lock_acquired   2016-03-29 06:37:28.9968693 1585440722              IX      1585440722  OBJECT          51          
lock_acquired   2016-03-29 06:37:28.9969268 7205759890195415040     IX      0           PAGE            51          1:1235
lock_acquired   2016-03-29 06:37:28.9969306 7205759890195415040     RI_NL   0           KEY             51          (ffffffffffff)
lock_acquired   2016-03-29 06:37:28.9969330 7205759890195415040     X       0           KEY             51          (29cf3326f583)
lock_released   2016-03-29 06:37:28.9969579 7205759890195415040     X       0           KEY             51          (29cf3326f583)
lock_released   2016-03-29 06:37:28.9969598 7205759890195415040     IX      0           PAGE            51          1:1235
lock_released   2016-03-29 06:37:28.9969607 1585440722              IX      1585440722  OBJECT          51      

Oluşturulan yeni satır için X tuş kilidinden hemen önce alınan RI_N KEY kilidini not alın. Bu kısa ömürlü menzil kilidi, eşzamanlı bir ekin RI_N kilitleri uyumlu olmadığından başka bir RI_N KEY kilidi almasını önleyecektir. 2. ve 3. adımlar arasında bahsettiğiniz pencere kaygı verici değil çünkü yeni oluşturulan anahtardaki satır kilidinden önce aralık kilidi alınmış.

Sürece senin kadar SELECT...ORDER BYistenen yeni eklenen satırlardan önce taramayı başlar, ben varsayılan içinde arzu davranışı beklenir READ COMMITTEDveritabanı sürece yalıtım düzeyi READ_COMMITTED_SNAPSHOTseçeneği kapalıdır.


1
Göre technet.microsoft.com/en-us/library/... , iki kilit RangeI_Nolan uyumlu yani (kilit olan bir seri okuyucu üzerinde bloke etmek için en çok var) birbirine engellemezler.
Fabian Schmied

@ FabianSchmied, ilginç. Bu konu technet.microsoft.com/en-us/library/ms186396(v=sql.105).aspx adresindeki kilit uyumluluk matrisi ile çakışıyor, bu kilitlerin uyumlu olmadığını gösteriyor. Bahsettiğiniz bağlantıdaki insert örneği, cevabımdaki izlemeyle aynı davranışı ifade eder (özel tuş kilidinden önce aralığı test etmek için kısa ömürlü insert aralığı kilidi).
Dan Guzman

1
Aslında, matris "çatışma yok" ("uyumlu değil" değil) için "N" diyor :) :)
Fabian Schmied

0

Benim SQL Server'ı anladığım kadarıyla, varsayılan davranış, ikinci sorgunun, ilk sorgunun yapılmasına kadar hiçbir sonuç göstermemesidir. İlk sorgu bir COMMIT yerine bir ROLLBACK yaparsa, sütununuzda eksik bir kimliğiniz olacaktır.

Temel yapılandırma

Veri Tabanı

Aşağıdaki yapıya sahip bir veritabanı tablosu oluşturdum:

CREATE TABLE identity_rc_test (
    ID4VALUE INT IDENTITY (1,1), 
    TEXTVALUE NVARCHAR(20),
    CONSTRAINT PK_ID4_VALUE_CLUSTERED 
        PRIMARY KEY CLUSTERED (ID4VALUE, TEXTVALUE)
)

Veri Tabanı İzolasyon Seviyesi

Veritabanımın izolasyon seviyesini aşağıdaki ifadeyle kontrol ettim:

SELECT snapshot_isolation_state, 
       snapshot_isolation_state_desc, 
       is_read_committed_snapshot_on
FROM sys.databases WHERE NAME = 'mydatabase'

Veritabanım için aşağıdaki sonucu veren:

snapshot_isolation_state    snapshot_isolation_state_desc   is_read_committed_snapshot_on
0                           OFF                             0

(Bu, SQL Server 2012'de bir veritabanı için varsayılan ayardır)

Test Scriptleri

Aşağıdaki komut dosyaları standart SQL Server SSMS istemci ayarları ve standart SQL Server ayarları kullanılarak yürütülmüştür.

İstemci bağlantı ayarları

İstemci, READ COMMITTEDSSMS'deki Sorgu Seçeneklerine göre İşlem İzolasyon Seviyesi'ni kullanacak şekilde ayarlanmıştır .

Sorgu 1

Aşağıdaki sorgu, SPID 57 ile bir Sorgu penceresinde yürütüldü.

SELECT * FROM dbo.identity_rc_test
BEGIN TRANSACTION [FIRST_QUERY]
INSERT INTO dbo.identity_rc_test (TEXTVALUE) VALUES ('Nine')
/* Commit is commented out to prevent the INSERT from being commited
--COMMIT TRANSACTION [FIRST_QUERY]
--ROLLBACK TRANSACTION [FIRST_QUERY]
*/

Sorgu 2

Aşağıdaki sorgu, SPID 58 ile bir Sorgu penceresinde yürütüldü.

BEGIN TRANSACTION [SECOND_QUERY]
INSERT INTO dbo.identity_rc_test (TEXTVALUE) VALUES ('Ten')
COMMIT TRANSACTION [SECOND_QUERY]
SELECT * FROM dbo.identity_rc_test

Sorgu tamamlanmadı ve eXclusive kilidinin bir PAGE üzerinde serbest bırakılmasını bekliyor.

Kilitlemeyi belirlemek için komut dosyası

Bu komut dosyası, iki işlem için veritabanı nesnelerinde oluşan kilitlemeyi görüntüler:

SELECT request_session_id, resource_type,
       resource_description, 
       resource_associated_entity_id,
       request_mode, request_status
FROM sys.dm_tran_locks
WHERE request_session_id IN (57, 58)

Ve işte sonuçlar:

58  DATABASE                    0                   S   GRANT
57  DATABASE                    0                   S   GRANT
58  PAGE            1:79        72057594040549300   IS  GRANT
57  PAGE            1:79        72057594040549300   IX  GRANT
57  KEY         (a0aba7857f1b)  72057594040549300   X   GRANT
58  KEY         (a0aba7857f1b)  72057594040549300   S   WAIT
58  OBJECT                      245575913           IS  GRANT
57  OBJECT                      245575913           IX  GRANT

Sonuçlar, sorgu penceresi bir'in (SPID 57), DATABASE'de Paylaşılan bir kilit (S), OBJECT üzerinde bir Amaçlı eXlusive (IX) kilidi, eklemek istediği PAGE üzerinde bir Amaçlı eXlusive (IX) kilidi ve bir eXclusive olduğunu göstermektedir KEY üzerine kilit (X) yerleştirilmiş, ancak henüz kaydedilmemiş.

Taahhüt edilmemiş verilerden dolayı, ikinci sorguda (SPID 58) DATABASE düzeyinde bir Paylaşılan kilit (S), OBJEK'de bir Amaçlanan Paylaşılan (IS) kilit, sayfada bir Amaçlanan Paylaşılan (IS) bir Paylaşılan (S) kilidi vardır. ) istek durumunda BEKLE tuşuyla KEY kilitleyin.

özet

İlk sorgu penceresindeki sorgu, taahhütte bulunmadan yürütülür. İkinci sorgu yalnızca READ COMMITTEDveri verebildiği için , zaman aşımı gerçekleşinceye kadar veya işlem ilk sorguda işlenene kadar bekler.

Bu benim anladığım kadarıyla Microsoft SQL Server'ın varsayılan davranışı.

İlk ifadenin KOMİTE olması durumunda, kimliğin SELECT ifadeleri tarafından sonraki okumalar için gerçekten sıralı olduğunu gözlemlemelisiniz.

İlk deyim bir ROLLBACK yaparsa, dizideki eksik bir kimliği bulursunuz, ancak yine de kimliği artan sırada (ID sütununda varsayılan veya ASC seçeneğini kullanarak INDEX oluşturduysanız) bulabilirsiniz.

Güncelleştirme:

(Açıkça söylemek gerekirse) Evet, bir sorunla karşılaşana kadar doğru çalışan kimlik sütununa güvenebilirsiniz. SQL Server 2000 ve Microsoft'un web sitesinde kimlik sütunu ile ilgili sadece bir HOTFIX var.

Doğru şekilde güncellenen kimlik sütununa güvenemezseniz, Microsoft'un web sitesinde daha fazla düzeltme veya düzeltme olacağını düşünüyorum.

Microsoft Destek Sözleşmeniz varsa, her zaman bir Danışma Davası açabilir ve ek bilgi isteyebilirsiniz.


1
Analiz için teşekkürler, ama sorum şu ki, bir sonraki Identitydeğerin üretilmesi ile satırdaki KEY kilidinin alınması arasında bir zaman penceresi varsa (eşzamanlı okuma / yazarların düşebileceği yer). Bunun gözlemlerinizin imkansız olduğunu düşünmüyorum çünkü bu çok kısa zaman dilimi boyunca sorgu yürütmeyi durduramaz ve kilitleri analiz edemezsiniz.
Fabian Schmied

Hayır, ifadeleri durduramazsınız, ancak (yavaş) gözlemim hızlı / normal bazda olan şeydir. Bir SPID veri eklemek için bir kilit alır almaz, diğeri aynı kilidi alamaz. Daha hızlı ifade, kilidi ve kimliği sırayla önceden edinmiş olma avantajına sahip olacaktır. Bir sonraki ifade, kilit açıldıktan sonra bir sonraki kimliği alacak.
John aka hot2use,

1
Normal olarak, gözlemleriniz benim (ve aynı zamanda beklentilerimin) uyuşuyor - bilmek güzel. Yine de beklemeyecekleri olağanüstü durumlar olup olmadığını merak ediyorum.
Fabian Schmied
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.