SQL Server “boş tablo” tüm (12 milyon) kayıt silindikten sonra yavaş mı?


27

Yaklaşık 150 sütun ile bir SQL Server 2008 örneği var. Bu tabloyu daha önce yaklaşık 12 milyon girişle doldurmuştum, ancak o zamandan beri tabloyu yeni bir veri seti hazırlarken temizledim.

Ancak, boş bir masaya anında ran bir kez gibi bu komutlar count(*)ve select top 1000de SQL Management Studioyayınlanması artık Eons alır.

SELECT COUNT(*) FROM TABLE_NAME 

0'a dönmek için 11 dakikadan fazla SELECT TOP 1000sürdü ve boş bir masaya geri dönmek için neredeyse 10 dakika sürdü.

Ayrıca, sabit diskimdeki boş alanın kelimenin tam anlamıyla kaybolduğunu da farkettim (yaklaşık 100G'den 20G'ye). Arasında olan tek şey koştuğum tek bir sorgu oldu:

DELETE FROM TABLE_NAME

Dünyada neler oluyor?


5
Veritabanınız hangi kurtarma modelini kullanıyor? Eğer "Dolu" ise, SQL örneğiniz boş alanınızın gittiği tüm silme işlemlerinin kaydını tutacaktır. Tam kurtarma bir zorunluluksa, TRUNCATE TABLEyerine kullanmanızı öneririm DELETE FROM.
Tullo_x86,

2
150 sütun? Bu masa çok fazla olabilir - çoğu tup çok daha küçük olmalıdır. Ancak tam bağlam olmadan söylemek imkansız.
Clockwork-Muse

Yanıtlar:


42

Size neden neden TRUNCATEbu kadar daha hızlı / daha iyi / daha seksi olacağı söylendi DELETE, ancak hala cevaplanması gereken bir soru var:

TamamlandıktanSELECT sonra neden daha yavaş ?DELETE

Çünkü DELETEsadece satırları hayaletleştirdi . Masa, 12M satır olduğu zamanki kadar büyük, hiçbiri olmamasına rağmen. Satırları (0) saymak, 12M satırlarını saymak kadar zaman alır. Zamanla hayalet temizleme işlemi, bu hayalet kayıtları toplar ve yalnızca hayaletleri içeren sayfaları dağıtır ve SELECT'leriniz hızlanır. Ancak şu anda Skipped Ghosted Records/secperfmon'u kontrol ederseniz büyük olasılıkla havaya uçuyor SELECT COUNT(*). Ayrıca tablo yeniden tarafından şeyleri hızlandırmak olabilir: ALTER TABLE ... REBUILD.

TRUNCATE Bunun arkasında hiçbir hayalet bırakmadığı için de bu sorunu çözmüş olacaktı.

Ayrıca bkz . Depolama Motorunun İçinde: Derinlemesine hayalet temizleme .


13

DELETEifadeler bir tablodaki satırları birer birer siler, her satırın girişini yapar ve bilgileri transaction logkorur log sequence number (LSN). Masanızın çok büyük verileri (12 milyon kayıt) olduğunu belirttiğinizden, Sabit diskinizin boş alanı kaldıktan sonra Veritabanı Günlüğü dosyanızın boyutunu kontrol edin. Muhtemelen büyüyecekti.

Daha iyi bir yol olurdu:

TRUNCATE TABLE_NAME

2
+1, tam olarak aynı DB için geçerli. Kayıtların günlüğe kaydedilmesine neden olan ifadeler kullanırsanız, zaman içinde veritabanını yavaşlatır.
Petro Semeniuk

@PetroSemeniuk Oracle'da hatırladığımdan itibaren, silme yalnızca yüksek su işaretini bırakır, kesik su suyunu sıfırlar. Tam tarama gerektiren herhangi bir işlemin yüksek su işaretine kadar blokları tarayacağına inanıyorum. Dolayısıyla silme, indekslenmiş işlemlere yardımcı olabilir, ancak taramalara değil. TRUNCATE uygun işlemdi.
Glenn

3

(Bu aslında @ DaveE'nin cevabına yapılan bir yorumdu, ancak uzun sürdüğü için kendi cevabını koydum)

TRUNCATE olan bir günlüğe çalışma. Aksi halde ACID uyumlu değildir. Ancak, TRUNCATEve arasındaki farklar DELETE:

  • Alan kullanımı günlüğü: TRUNCATEyalnızca sayfaları / uzantıları * serbest bırakır , oysa DELETEbireysel satırları günlüğe kaydeder.
  • Kilit kullanımı: TRUNCATEgenellikle daha az kilit kullanacaktır, çünkü DELETEsıra kilit kullanan ** , bir tablo kilidi ve sayfa kilitleri alır .
  • IDENTITYsekanslar: TRUNCATEVarsa, tablodaki kimlik sekansını sıfırlar.

(* Bir kapsam = 8 sayfa TRUNCATE, hepsi bu tablodan çıkarsa uzantıları günlüğe kaydeder / kaldırır, aksi halde karışık uzantılardan sayfaları günlüğe kaydeder / kaldırır.

** Bunun bir yan etkisi DELETE FROM TABLE, operasyonun özel bir masa kilidi alıp alamayacağına bağlı olarak tabloya ayrılmış boş sayfaları potansiyel olarak boş bırakmasıdır.)

Yani (asıl soruya dönersek), masayı boşalttığınızdan ama yapıyı korumak istemenizden TRUNCATE TABLEkesinlikle daha iyidir DELETE FROM TABLE(NB: TRUNCATEbaşka bir tablodan gelen yabancı bir anahtar tarafından başvurulan bir masada kullanılamaz).

@ Tullo'nun yorumunda belirtildiği gibi, veritabanınızın kurtarma modelini de kontrol edin - eğer doluysa, ya günlük yedeklemeleri almaya başlamanız ya da kurtarma modelinizi basit olarak değiştirmeniz gerekir. Bunlardan birini yaptıktan sonra, tüm bu boş alanı geri kazanmak için günlük dosyanızı bir kereye mahsus bir işlem ( yalnızca NB: günlük dosyası ) olarak daraltmak istersiniz .

Son olarak, farkında olmak için başka bir şey - tablo istatistikleri. UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE` komutunu çalıştırın, böylece sorgu optimizatörü eski istatistiklere göre uyarılmaz.


2

(NOT: DBA değilim) DELETE günlüğe kaydedilmiş bir işlemdir ve kullanılan alanı boş bırakmaz. Muhtemelen 'boş' tablo alanında çalışan alan ve tablo taramaları alan büyük bir işlem günlüğünüz vardır. İşlem günlüğünü temizlemeniz ve veritabanınızı küçültmeniz gerektiğini tahmin ediyorum. Bu StackOverflow makalesinin başlamanız gerekir.

Ve ileride bunu yapmak istediğinizde TRUNCATE TABLE'ı kullanın.

DÜZENLEME: TRUNCATE günlüğe kaydedilmemiş hakkında benim deyim hata oldu. çıkarıldı.

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.