100mm kayıtlarda JOIN ile GÜNCELLEME, bunu nasıl daha iyi yapabilirim? (T-SQL'de)


11

Tek bir tabloda 100 milyon kayıt güncellemeliyim, aslında, bir sütunun varchar değerini sadece bir ID ile değiştirerek tabloyu normalleştiriyorum. ("Değiştiriyorum" diyorum ama gerçekten kimliği başka bir sütuna yazıyorum.)

Elde etmeye çalıştığım, veri kümesini normalleştirmek. Henüz normalleştirilmemiş verilerin indekslenmesi yoktur. Benim düşüncem, güncelleme tamamlandıktan sonra varchar değerlerini tinyint değerleriyle değiştirecek yabancı anahtarları endekslemek için beklemek yerine ham değerler üzerinde dizinler oluşturmayacağımdı.

UPDATE A
SET A.AutoClassID = B.AutoClassID
FROM AutoDataImportStaging.dbo.Automobile as A
JOIN AutoData.dbo.AutoClass as B on (A.AutoClassName = B.AutoClassName)

Arka fon

  • 2008 R2 üzerinde MSSQL 2008 R2 kullanma
  • Sunucuda 8 GB RAM var
  • sunucunun bir RAID10, 7200 RPM SATA'sı var (çok iyi değil, biliyorum, üretimde bu sadece verileri okuyacak ve veri yazmayacak; artı son HD sıkıntısı bunu maliyet için gerekli hale getirdi)
  • sunucusu çift dört çekirdekli Xeon CPU'ya sahip
  • Makine başka bir şey yapmıyor (şu anda geliştirmeye adanmış, sadece bu işlem)
  • basit günlük kaydı açıldı (? - ancak geri dönebilmesi için hala günlüğe kaydediliyor mu?)
  • sorgunun değerine göre iki farklı DB'ye başvurduğunu unutmayın
  • güncellenen tablodaki bir kaydın "genişliği" 455 bayt

Yürütme Sırasında Kaynaklar

  • fiziksel RAM maksimum
  • disk G / Ç maks.
  • CPU neredeyse hiçbir şey yapmıyor (boğulma noktası G / Ç)
  • çalışma süresi 14 saat oldu ve sayılıyor!

Normalleştirme güncellemelerinden sonra sütunu (AutoClassName) bırakacak olsam bile, ham verilerde bir dizine ihtiyacım var gibi birkaç şeyden şüpheleniyorum. Ayrıca, bunu başlattığımda saçma görünen JOIN yerine masayı bir kerede bir rekor kırabilir miyim, ama şimdi daha hızlı olurdu gibi görünüyor.

Kalan normalleştirme güncellemelerim (buna benzer) için yöntemimi daha hızlı bir şekilde nasıl değiştirmeliyim?

Yanıtlar:


7

Bunu tek (çok büyük) bir işlem olarak yapmaya çalışıyorsunuz. Bunun yerine, güncellemeyi daha küçük gruplar halinde yapın.

Ayrıca şunlardan da yararlanabilirsiniz:

  • AutoData.dbo.AutoClass.AutoClassName üzerinde geçici bir dizin
  • Daha fazla RAM. Çok daha fazla RAM.

1
+1 Maddeyi kullanarak toplu güncellemeye katılıyorum TOP. Benim yaklaşımım bu olurdu.
Thomas Stringer

UPDATE TOP yaparsam bir WHERE yantümcesine ihtiyacım olacak (NEREDE AutoClassID NULL)? WHERE deyimi yeni bir performans isabeti getirmez mi (şu anda yapmadığım bir tablo taraması). Şüphesiz JOIN ile yaşadığım RAM problemini azaltacaktır.
Chris Adragna

Benim yanıtım gecikmiş, ama benim durumumda SET ROWCOUNT en etkili olduğunu kanıtladı.
Chris Adragna

10

Farklı bir yaklaşım sergileyeceğim.

Mevcut tabloları güncellemek yerine, içinde ihtiyacınız olan şeyleri içeren yeni bir tablo oluşturun.

Bu neredeyse kesinlikle daha hızlı olacak:

SELECT DISTINCT
    AutoClassID,
    <Other fields>
INTO
    AutoDataImportStaging.dbo.Automobile
FROM
    AutoData.dbo.AutoClass

Şu anda yazıldığı gibi, birçok mantıksal işlem gerçekleşiyor:

  • A.AutoClassName öğesinin tüm değerlerini okuyun
  • B.AutoClassName öğesinin tüm değerlerini okuyun
  • A ve B değerlerini karşılaştırın
  • Eşleşen kümede, B.AutoClassID öğesinin tüm değerlerini okuyun
  • A.AutoClassId'in varolan değerlerini, varolan dizinlerden B.AutoClassId değeri olacak şekilde güncelleyin

Bu güzel, basit bir yaklaşım gibi geliyor, özellikle disk I / O problemi göz önüne alındığında. Bu kadar çabuk cevap verdiğiniz için teşekkürler.
Chris Adragna

1
Günlük ve veri dosyalarınızda yeterli boş alan olup olmadığını iki kez kontrol etmenizi öneririm. Dosyalar otomatik olarak büyüyorsa, performans düşecektir. Sıklıkla bazı büyük, bir kerelik güncellemeler çalıştıran ve günlük dosyalarını fark etmeden otomatik olarak büyüten insanlar görüyorum.
darin boğazı

5

Masayı bir seferde bir satır döngü, daha hızlı olmayacak!

Şüphelendiğiniz ve sizin tarafınızdan onaylandığı gibi, bu bir I / o bağlı olacaktır - bir diske sahip olmak, okuma, yazma, işlem günlükleri ve (herhangi bir) geçici çalışma alanı aynı i / o için yarışacaktır.

Basit kurtarma yine de işlemleri günlüğe kaydeder, ancak günlük bir denetim noktası tarafından temizlenir. İlk günlük boyutu ve otomatik büyüme ayarlarının bir miktar g / Ç yavaşlamasına neden olması mümkündür - değişikliklerin gerçekleşmesi için işlem günlüğünün büyümesi gerekir.

AutoClassName alanını dizine eklemeyi denediniz mi? Kaç farklı AutoClass değeri var?

G / Ç sınırlamalarınızı temel alarak güncellemeleri toplu olarak oluşturmanız gerekebilir. Yani 1 milyon güncelleme, kontrol noktası, tekrar ....


Yalnızca 15 farklı AutoClass değeri vardır. Yorumlarınız şüphelerimin çoğunu (ve acılarımı!) Onaylıyor. Cevap verdiğiniz için teşekkür ederim.
Chris Adragna

3

Birleştirme alanları için dizinler oluşturun.

İşiniz bittiğinde dizinleri istediğiniz zaman bırakabilirsiniz.

Dizinler güncelleme performansını önemli ölçüde iyileştirmediyse çok şaşırırdım.


Eminim dizinler gelişir. Ben soru (sadece bir kullanım için) dizin oluşturmak için gereken süreden daha fazla geliştirmek olup olmadığını varsayalım. Muhtemelen evet. :)
Chris Adragna

3

İstediğiniz şekilde dışa aktarın, yeni bir tablo oluşturun ve geri içe aktarın. Bir bonus olarak, mucizeler meydana gelirse verilerin yedek olarak bir kopyasına sahip olursunuz.

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.