NOLOCK ipucu, döndürülen kayıtların sırasını değiştirir


11

Tablo Clientalanında kümelenmiş bir dizin var LastName.

Sadece tüm kayıtları tablodan dökümü, (nolock)ipucu söz konusu sorguda olduğu gibi kullanılmadıkça alfabetik sırayla görünür . Bu ipucu kayıtların sırasını değiştirir. Olmalı mı? Başka hiçbir oturumun bu tablodaki değişikliklerle açık bir işlemi olmadığından eminim (en azından sp_who2bana hiç göstermiyor).

Sıradaki fark nasıl açıklanabilir?

Yorumlardan alınan ek bilgiler:

  1. Tarafından sipariş yok. Kümelenmemiş dizin siparişi zorunlu kılmalı mı?

  2. Kümelenmiş bir dizin belirten bir dizin ipucu kullanıldığında bile sorgular farklı bir sıra döndürür. Yapmalılar mı? nolockPlanların görünür bir değişikliği olmadan neden iade edilen kayıtların sırasını değiştirdiğini merak ediyorum .

  3. Onları WinDiff yaptım - aynı (nolock)[sorgu] ipucu hariç .


21
İpucu, siparişi değiştirmez
a_horse_with_no_name 2:15

Yanıtlar:


47

Sıralı bir sonuç kümesinin, bir ORDER BYcümle olmadan görünümü , çoğunlukla, dizinleri sıralamasında satırları alan bir taramadan kaynaklanır. Bir dizin sırası taramasının genellikle varsayılan READ COMMITTEDyalıtım düzeyi altında seçilmesinin bir nedeni , aynı satıra birden çok kez rastlamak veya bazı satırları tamamen atlamak gibi istenmeyen eşzamanlılık anormalliklerini azaltmasıdır. Bu, izolasyon seviyeleri ile ilgili bu makale dizisi de dahil olmak üzere çeşitli yerlerde ayrıntılıdır .

Bir ile NOLOCKtablo ipucu, bu davranış, gevşetilir ve masaya erişim daha toleranslı altında gerçekleştirilir READ UNCOMMITTEDolabilir yalıtım seviyesi, ayırma amacıyla veri tarama yerine göstergesi için. Bu bağlantıda açıklandığı gibi, bir ayırma sırası veya dizin sırası taraması kullanmayla ilgili karar depolama motoruna bırakılır. Bu seçim, sorgu planında değişiklik yapılmadan yürütmeler arasında değişebilir .

Bu çok soyut gelebilir, ancak AdventureWorks2012 veritabanına karşı belgelenmemiş işlevler kullanan bazı sorgularda daha kolay gösterilebilir .

USE AdventureWorks2012;
GO
-- Appears to be ordered by BusinessEntityID
-- File:Page:Slot goes up and down several times
-- Show physical locations with sys.fn_PhysLocFormatter (undocumented)
SELECT
    P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P;

-- Same query with TABLOCK or NOLOCK
-- Allocation-order (IAM) scan
-- Now appears to be ordered by File:Page:Slot instead of BusinessEntityID
SELECT P.BusinessEntityID,
    [(File:Page:Slot)] =
        sys.fn_PhysLocFormatter(%%physloc%%)
FROM Person.Person AS P WITH (NOLOCK);

Sorgu Sonuçları

Sorgular Paul White'dan küçük bir değişiklikle ödünç alındı .

Son olarak, net olmak gerekirse, bu cevap sıralı bir sonuç kümesinin ortaya çıkmasıyla ilgilidir. Orada hiçbir sunum sırası garanti bir üst düzey olmadan ORDER BY.

Bir tablo düzeyinde kilit alındığında veya veritabanının salt okunur modda olduğu gibi çeşitli diğer durumlarda ayırma sırası taraması oluşabilir. Paralellik aynı zamanda verilerin iade edilme sırasını da etkileyebilir. Kilit nokta, ORDER BYsipariş verilerinin geri gönderilmesinin zaman içinde tasarım gereği değişebilmesidir.


7
Güzel, benim eşsiz girişimimden çok daha spesifik. Elbette son iki paragrafınızda. "Neden" sonunda gerçekten önemli değil. Belki de bu akoru benden daha iyi vurursun.
Aaron Bertrand

12

Tablodaki tüm kayıtları döktüğümde

... o zaman herhangi bir emir beklememelisiniz. Aslında, birden çok kez çalıştırılan aynı sorgu uyarı yapılmadan farklı bir sırada geri gelebilir. Bunun nedeni, ipucu nedeniyle değil, farklı sorgu metni nedeniyle büyük olasılıkla "farklı" sorgular olan iki sorgunuzun farklı yürütme planlarına sahip olmasıdır (ve fark, aynı görünen bir yineleyici gibi ince olabilir) her ikisi de planlar, ancak ordered: trueyalnızca bir tanesine sahiptir veya büyük bir veri değişikliğinden önce derlendiğinden çok farklı sayıda tahmini satır vardır). James'in cevabında haklı olarak belirttiği gibi, bir tahsisat emri taranması da olabilir.

Her durumda, olmadan bir sorgu çalıştırdığınız için ORDER BY, SQL Server sipariş umurumda değil ve bu yüzden gider ve satırları döndürmek için en etkili yolu belirler (eğer yoksa sipariş umurumda değil) ).

Bunu çok netleştireyim:

Belirli bir sipariş istiyorsanız veya beklerseniz, ORDER BY deyimi ekleyin

Bu daha önce ortaya çıktı:

Ve bu konuda blog yazdım:

İşte ikincisinden bir ORDER BYcümle yerine bir dizin ipucu kullanma hakkındaki yorumunuzu ele almak için söylediklerimi tekrarlayan bir alıntı :

İpucu içeren bir dizin söz konusu olduğunda bile, dizin kullanılır (mümkünse, çoğu durumda başka bir hata), ancak dizin kullanılması nedeniyle sonuçların, bu endeks. ORDER BYİndeks anahtar (lar) ına göre sıralama yapmak için hala bir a ihtiyacınız vardır .

Conor Cunningham - oldukça akıllı bir adam, SQL Server sizin için bir sorguyu işlediğinde yaptıklarının çoğundan doğrudan sorumlu - burada da blog yazdı:

Lütfen biraz okuma yapın ve ardından ORDER BYfarklı veya beklenmedik sıralamadan şikayet etmeden önce sorgularınıza bir cümle ekleyin .


11

James bunun nasıl çalıştığını güzelce açıkladı, ama sadece bir şeyi tekrarlamak istiyorum: bir sipariş fonksiyonu kullanmazsanız, sonuç kümesindeki satırların sırası tanımsızdır . Belirli bir siparişe ihtiyacınız varsa, açık bir order bycümle kullanın - belirtmezseniz, temel olarak "Kümelenmiş dizine göre sırala" değil, "Siparişi hiç umursamıyorum" diyorsunuz.

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.