SQL Server "tabel kosong" lambat setelah menghapus semua (12 juta) catatan?

27

Saya punya contoh SQL Server 2008 dengan sekitar 150 kolom. Saya sebelumnya telah mengisi tabel ini dengan sekitar 12 juta entri, tetapi sejak itu membersihkan tabel dalam persiapan untuk kumpulan data baru.

Namun, perintah yang pernah berlari langsung pada sebuah meja kosong seperti count(*)dan select top 1000di SQL Management Studiosaat mengambil ribuan tahun untuk menjalankan.

SELECT COUNT(*) FROM TABLE_NAME 

butuh lebih dari 11 menit untuk mengembalikan 0, dan SELECT TOP 1000butuh hampir 10 menit untuk mengembalikan meja kosong.

Saya juga memperhatikan bahwa ruang kosong pada hard drive saya benar-benar menghilang (turun dari sekitar 100G ke 20G). Satu-satunya hal yang terjadi di antaranya adalah satu kueri yang saya jalankan:

DELETE FROM TABLE_NAME

Apa yang sedang terjadi?!?


sumber
5
Model pemulihan apa yang digunakan database Anda? Jika "Penuh", instance SQL Anda akan menyimpan catatan semua penghapusan itu, yang bisa menjadi tempat ruang kosong Anda pergi. Jika pemulihan penuh adalah suatu kebutuhan, saya sarankan menggunakan TRUNCATE TABLEbukan DELETE FROM.
Tullo_x86
2
150 kolom? Tabel itu mungkin terlalu penuh - kebanyakan tupel harus jauh lebih kecil. Namun, mustahil untuk mengatakan tanpa konteks penuh.
Clockwork-Muse

Jawaban:

42

Anda telah diberi tahu tentang mengapa TRUNCATEakan jauh lebih cepat / lebih baik / lebih seksi daripada DELETE, tetapi masih ada pertanyaan yang harus diatasi:

Mengapa SELECTlebih lambat setelah DELETE selesai ?

Itu karena DELETEhanya membayangi baris. Tabel ini hanya sebesar ketika memiliki 12M baris, meskipun tidak ada. Untuk menghitung baris (0), dibutuhkan waktu sebanyak yang diperlukan untuk menghitung 12M baris. Pada saatnya proses pembersihan hantu akan mengumpulkan sampah catatan hantu ini dan mengalokasikan halaman yang hanya berisi hantu, dan SELECT Anda akan mempercepat. Tetapi sekarang jika Anda check- Skipped Ghosted Records/secin perfmon mungkin meroket selama SELECT COUNT(*). Anda juga bisa mempercepat hal-hal dengan membangun kembali tabel: ALTER TABLE ... REBUILD.

TRUNCATE akan juga mengurus masalah ini, karena tidak meninggalkan hantu di belakang.

Lihat juga Di dalam Mesin Penyimpanan: Pembersihan hantu secara mendalam .

Remus Rusanu
sumber
13

DELETEpernyataan menghapus baris dari tabel satu per satu, mencatat setiap baris dalam transaction log, serta memelihara log sequence number (LSN)informasi. Karena Anda menyebutkan meja Anda memiliki data yang sangat besar (12 juta catatan), setelah penghapusan Hard Disk Anda kehabisan ruang, periksa ukuran file Log Database Anda. Kemungkinan besar akan tumbuh.

cara yang lebih baik adalah:

TRUNCATE TABLE_NAME

sumber
2
+1, persis benar sama untuk Oracle DB. Jika Anda menggunakan pernyataan yang menyebabkan catatan untuk log, itu akan memperlambat basis data dari waktu ke waktu.
Petro Semeniuk
@PetroSemeniuk Dari apa yang saya ingat di Oracle, hapus meninggalkan tanda air tinggi saja, truncate akan mengatur ulang tanda air tinggi. Saya percaya setiap operasi yang memerlukan pemindaian penuh akan memindai blok sampai tanda air tinggi. Oleh karena itu menghapus dapat membantu operasi yang diindeks, tetapi tidak memindai. TRUNCATE adalah operasi yang tepat.
Glenn
3

(Ini awalnya adalah komentar untuk jawaban @ DaveE, tapi saya sudah memasukkannya ke dalam jawabannya sendiri karena sudah lama)

TRUNCATE adalah operasi yang dicatat. Itu harus dinyatakan tidak memenuhi syarat ACID. Namun, perbedaan antara TRUNCATEdan DELETE:

  • Penggunaan ruang log: TRUNCATEhanya log halaman / luasan * yang dibebaskan, sedangkan DELETElog setiap baris.
  • Penggunaan kunci: TRUNCATEumumnya akan menggunakan lebih sedikit kunci, karena dibutuhkan kunci meja dan kunci halaman, sebagai lawan dari DELETEyang menggunakan kunci baris **.
  • IDENTITYurutan: TRUNCATEmengatur ulang urutan identitas pada tabel, jika ada.

(* Tingkat = 8 halaman. TRUNCATEAkan mencatat / menghapus luasan jika semuanya dari satu tabel itu, jika tidak maka akan mencatat / menghapus halaman dari luasan campuran.

** Satu efek samping dari hal ini adalah bahwa DELETE FROM TABLEberpotensi dapat membiarkan halaman kosong dialokasikan ke tabel, tergantung pada apakah operasi bisa mendapatkan kunci tabel eksklusif atau tidak.)

Jadi (kembali ke pertanyaan awal), TRUNCATE TABLEkonklusif lebih baik daripada DELETE FROM TABLEjika Anda mengosongkan tabel tetapi ingin mempertahankan strukturnya (NB: TRUNCATEtidak dapat digunakan pada tabel yang dirujuk oleh kunci asing dari tabel lain).

Seperti tercantum dalam komentar @ Tullo, periksa juga model pemulihan basis data Anda - jika penuh, maka Anda harus mulai mengambil cadangan log, atau mengubah model pemulihan menjadi sederhana. Setelah Anda melakukan salah satu dari itu, Anda mungkin ingin mengecilkan file log Anda sebagai operasi sekali saja (NB: file log saja ) untuk mendapatkan kembali semua ruang kosong itu.

Akhirnya, hal lain yang perlu diperhatikan - tabel statistik. jalankan UPDATE STATISTICS <TABLENAME>' afterTRUNCATE /DELETE` sehingga optimizer kueri tidak tersandung oleh statistik lama.

Simon Righarts
sumber
2

(CATATAN: Saya bukan DBA) DELETE adalah operasi yang dicatat, dan tidak membebaskan ruang yang digunakan. Anda mungkin memiliki log transaksi besar yang mengambil ruang dan pemindaian tabel berjalan di ruang tabel 'kosong'. Saya kira Anda perlu menghapus log transaksi dan mengecilkan basis data Anda. Artikel StackOverflow ini akan membantu Anda memulai.

Dan gunakan TRUNCATE TABLE ketika Anda ingin melakukan ini di masa depan.

EDIT: Pernyataan saya tentang TRUNCATE yang tidak dicatat salah. dihapus.

DaveE
sumber