Bireysel ifadeler - DML, DDL, vb. - kendi içlerinde işlemlerdir. Yani evet, döngünün her yinelemesinden sonra (teknik olarak: her ifadeden sonra), bu UPDATE
ifade ne olursa olsun otomatik olarak taahhüt edilmiştir.
Tabii ki, her zaman bir istisna vardır, değil mi? Örtülü İşlemleri SET IMPLICIT_TRANSACTIONS aracılığıyla etkinleştirmek mümkündür , bu durumda ilk UPDATE
ifade, yapmanız gereken COMMIT
veya ROLLBACK
sonunda yapacağınız bir işlemi başlatır . Bu, çoğu durumda varsayılan olarak KAPALI olan bir oturum düzeyi ayarıdır.
istediğiniz zaman iptal edebilmemiz için açık BEGIN TRANSACTION / END TRANSACTION ifadeleri eklememiz gerekir mi?
Hayır. Ve aslında, süreci durdurmak ve yeniden başlatmak istediğiniz göz önüne alındığında, açık bir işlem eklemek (veya Örtülü İşlemleri etkinleştirmek) kötü bir fikir olacaktır çünkü işlemin durdurulması işlemi gerçekleştirmeden önce yakalayabilir COMMIT
. Bu durumda COMMIT
(SSMS'deyseniz) el ile vermeniz gerekir veya bunu bir SQL Agent işinden çalıştırıyorsanız, bu fırsatınız olmaz ve artık bir işlemle sonuçlanabilir.
Ayrıca, @CHUNK_SIZE
daha küçük bir sayıya ayarlamak isteyebilirsiniz . Kilit yükseltme genellikle tek bir nesnede elde edilen 5000 kilitte gerçekleşir. Satırların boyutuna bağlı olarak ve Satır kilitleri ile Sayfa kilitleri karşılaştırması yapıyorsa, bu sınırı aşmış olabilirsiniz. Bir satırın boyutu her sayfa için yalnızca 1 veya 2 satır sığacak şekildeyse, Sayfa kilitleri yapsa bile buna her zaman çarpıyor olabilirsiniz.
Tablo bölümlenmişse, tabloyu LOCK_ESCALATION
(SQL Server 2008'de tanıtıldı) seçeneğini AUTO
, tırmanma sırasında tüm tabloyu değil tüm bölümü kilitleyecek şekilde ayarlama seçeneğiniz vardır . Veya, herhangi bir tablo için aynı seçeneği ayarlayabilirsiniz DISABLE
, ancak bu konuda çok dikkatli olmanız gerekir. Bkz alter table Ayrıntılar için.
Kilit Yükseltme ve eşikler hakkında konuşan bazı belgeler: Kilit Yükseltme ("SQL Server 2008 R2 ve daha yüksek sürümler için geçerlidir"). Ve burada kilit yükselme tespit ve düzeltme ile ilgili bir blog yazısı: Microsoft SQL Server'da Kilitleme (Bölüm 12 - Kilit Yükseltme) .
Tam soru ile ilgisi yoktur, ancak sorudaki sorgu ile ilgili olarak, burada yapılabilecek birkaç iyileştirme vardır (veya en azından sadece ona bakmaktan böyle görünüyor):
WHILE (@@ROWCOUNT = @CHUNK_SIZE)
Döngünüz için, son yinelemede güncellenen satır sayısı GÜNCELLEME için istenen miktardan azsa , yapmak biraz daha iyidir, o zaman yapacak hiçbir iş kalmaz.
Eğer deleted
alan bir olan BIT
veri türü, daha sonra alıp almamalarına değer belirlemiş değil deletedDate
ise 2000-01-01
? Neden ikisine de ihtiyacınız var?
Bu iki alan yeniyse ve bunları NULL
çevrimiçi / engellemeyen bir işlem olabilir ve şimdi "varsayılan" değerlerine güncellemek istiyorsanız , bu gerekli değildi. SQL Server 2012'den (yalnızca Enterprise Edition) başlayarak, NOT NULL
DEFAULT kısıtlaması olan sütunlar eklemek , DEFAULT değeri sabit olduğu sürece engelleme olmayan işlemlerdir. Bu nedenle henüz alanları kullanmıyorsanız, NOT NULL
DEFAULT kısıtlaması olarak bırakıp yeniden ekleyin .
Bu GÜNCELLEME'yi gerçekleştirirken bu alanları güncelleyen başka bir işlem yoksa, güncelleştirmek istediğiniz kayıtları sıraya koyduysanız ve daha sonra yalnızca bu kuyruğu kapatırsanız daha hızlı olur. Değiştirilmesi gereken seti almak için her seferinde tabloyu yeniden sorgulamanız gerektiğinden geçerli yöntemde bir performans isabeti vardır. Bunun yerine, tabloyu bu iki alanda yalnızca bir kez tarayan ve daha sonra yalnızca çok hedefli UPDATE deyimleri yayınlayan aşağıdakileri yapabilirsiniz. Ayrıca, işlemin herhangi bir zamanda durdurulmasından ve daha sonra başlatılmasından herhangi bir ceza yoktur, çünkü kuyruğun ilk nüfusu güncellenecek kalan kayıtları bulacaktır.
- Kümelenmiş dizindeki anahtar alanları içeren geçici bir tablo (#FullSet) oluşturun.
- Aynı yapının ikinci bir geçici tablosunu (#CurrentSet) oluşturun.
üzerinden #FullSet'e ekle SELECT TOP(n) KeyField1, KeyField2 FROM [huge-table] where deleted is null or deletedDate is null;
TOP(n)
Nedeniyle tablonun büyüklüğüne orada. Tablodaki 100 Milyon satır ile, özellikle işlemi sık sık durdurmayı ve daha sonra yeniden başlatmayı planlıyorsanız, kuyruk tablosunu tüm anahtar kümesiyle doldurmanıza gerek yoktur. Bu yüzden belki n
1 milyona ayarlandı ve tamamlanmasına izin ver. Bunu her zaman 1 milyon (veya belki daha az) kümesini çalıştıran bir SQL Agent işinde zamanlayabilir ve daha sonra bir sonraki planlanan sürenin tekrar toplanmasını bekleyebilirsiniz. Daha sonra, her 20 dakikada bir çalışmayı planlayabilirsiniz, böylece setler arasında zorlanmış bir solunum odası n
olacaktır, ancak yine de tüm süreci katılımsız olarak bitirecektir. Daha sonra yapacak bir şey olmadığında işin kendisini silmesini sağlayın :-).
- bir döngüde şunları yapın:
- Geçerli toplu işi benzer bir şeyle doldurma
DELETE TOP (4995) FROM #FullSet OUTPUT Deleted.KeyField INTO #CurrentSet (KeyField);
IF (@@ROWCOUNT = 0) BREAK;
- UPDATE gibi bir şey kullanarak yapın:
UPDATE ht SET ht.deleted = 0, ht.deletedDate='2000-01-01' FROM [huge-table] ht INNER JOIN #CurrentSet cs ON cs.KeyField = ht.KeyField;
- Geçerli seti temizle:
TRUNCATE TABLE #CurrentSet;
- Bazı durumlarda
SELECT
, #FullSet
geçici tabloya beslenmesine yardımcı olmak için bir Filtrelenmiş Dizin eklemek yardımcı olur . İşte böyle bir dizin eklemeyle ilgili bazı noktalar:
- WHERE koşulu, sorgunuzun WHERE koşuluyla eşleşmelidir;
WHERE deleted is null or deletedDate is null
- İşlemin başlangıcında, çoğu satır WHERE koşulunuzla eşleşir, bu nedenle bir dizin o kadar da yararlı değildir. Bunu eklemeden önce% 50 civarında bir yere kadar beklemek isteyebilirsiniz. Tabii ki, ne kadar yardımcı olur ve endeksi eklemenin en iyi olduğu zaman birkaç faktörden dolayı değişir, bu yüzden biraz deneme yanılmadır.
- Temel veriler oldukça sık değiştiği için, istatistikleri manuel olarak GÜNCELLEMEK ve / veya dizini tekrar güncellemek zorunda kalabilirsiniz
- Dizin, yardımcı olurken
SELECT
, UPDATE
bu işlem sırasında güncellenmesi gereken başka bir nesne, dolayısıyla daha fazla G / Ç olduğu için zarar vereceğini unutmayın . Bu, hem Filtrelenmiş Bir Dizini (daha az sayıda satır filtreyle eşleştiği için satırları güncellediğinizde küçülür) hem de dizini eklemek için biraz beklerken (başlangıçta süper yardımcı olmayacaksa, bunun için bir neden yok) ek G / Ç).
GÜNCELLEME: Durumu izlemek ve temiz bir şekilde iptal etmek için bir mekanizma da dahil olmak üzere yukarıda önerilenlerin tam olarak uygulanması için bu soru ile ilgili bir soruya cevabımı bakın: sql server: küçük parçalar halinde büyük tablodaki alanları güncelleme: nasıl alınır ilerleme / durumu?