it-swarm.asia

Metode mempercepat DELETE FROM besar dari <tabel> tanpa klausa

Menggunakan SQL Server 2005.

Saya melakukan DELETE FROM besar tanpa klausa mana. Ini pada dasarnya setara dengan pernyataan TRUNCATE TABLE - kecuali saya tidak diizinkan untuk menggunakan TRUNCATE. Masalahnya adalah meja sangat besar - 10 juta baris, dan dibutuhkan lebih dari satu jam untuk menyelesaikannya. Apakah ada cara untuk membuatnya lebih cepat tanpa:

  • Menggunakan Truncate
  • Menonaktifkan atau menjatuhkan indeks?

Log-t sudah ada di disk terpisah.

Ada saran!

37
tuseau

Apa yang dapat Anda lakukan adalah penghapusan batch seperti ini:

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable

Di mana xxx, katakanlah, 50000

Modifikasi ini, jika Anda ingin menghapus persentase baris yang sangat tinggi ...

SELECT col1, col2, ... INTO #Holdingtable
           FROM MyTable WHERE ..some condition..

SELECT 'Starting' --sets @@ROWCOUNT
WHILE @@ROWCOUNT <> 0
    DELETE TOP (xxx) MyTable WHERE ...

INSERT MyTable (col1, col2, ...)
           SELECT col1, col2, ... FROM #Holdingtable
39
gbn

Anda bisa menggunakan klausa TOP untuk menyelesaikan ini dengan mudah:

WHILE (1=1)
BEGIN
    DELETE TOP(1000) FROM table
    IF @@ROWCOUNT < 1 BREAK
END
21
SQLRockstar

Saya setuju dengan saran untuk mengelompokkan penghapusan Anda ke dalam potongan yang dapat dikelola jika Anda tidak dapat menggunakan TRUNCATE, dan saya suka saran drop/create untuk orisinalitasnya, tetapi saya ingin tahu tentang komentar berikut dalam pertanyaan Anda:

Ini pada dasarnya setara dengan pernyataan TRUNCATE TABLE - kecuali saya tidak diizinkan menggunakan TRUNCATE

Saya menduga alasan pembatasan ini berkaitan dengan keamanan yang perlu diberikan untuk langsung memotong tabel dan fakta bahwa itu akan memungkinkan Anda untuk memotong tabel selain dari yang Anda khawatirkan.

Dengan asumsi itu yang terjadi, saya bertanya-tanya apakah memiliki prosedur tersimpan dibuat yang menggunakan TRUNCATE TABLE dan menggunakan "EXECUTE AS" akan dianggap sebagai alternatif yang layak untuk memberikan hak keamanan yang diperlukan untuk memotong tabel secara langsung.

Mudah-mudahan, ini akan memberi Anda kecepatan yang Anda butuhkan sambil juga mengatasi masalah keamanan yang mungkin dimiliki perusahaan Anda dengan menambahkan akun Anda ke peran db_ddladmin.

Keuntungan lain dari menggunakan prosedur tersimpan dengan cara ini adalah prosedur tersimpan itu sendiri dapat dikunci sehingga hanya akun tertentu yang diizinkan untuk menggunakannya.

Jika karena alasan tertentu ini bukan solusi yang dapat diterima dan kebutuhan Anda untuk menghapus data dalam tabel ini adalah sesuatu yang perlu dilakukan sekali sehari/jam/dll, saya akan meminta agar pekerjaan SQL Agent dibuat untuk memotong tabel pada waktu yang dijadwalkan setiap hari.

Semoga ini membantu!

7
Jeff

Kecuali terpotong .. hanya menghapus dalam batch yang dapat membantu Anda.

Anda dapat menjatuhkan tabel dan membuatnya kembali, dengan semua kendala dan indeks, tentunya. Di Studio Manajemen Anda memiliki opsi untuk membuat skrip tabel untuk dijatuhkan dan dibuat, jadi itu harus menjadi opsi sepele. Tapi ini hanya jika Anda diizinkan untuk melakukan tindakan DDL, yang saya lihat itu bukan pilihan.

5
Marian

Karena pertanyaan ini adalah referensi penting, saya memposting kode ini yang benar-benar membantu saya memahami penghapusan dengan loop dan juga pesan dalam satu lingkaran untuk melacak kemajuan.

Permintaan dimodifikasi dari this pertanyaan rangkap. Kredit ke @ RLF untuk basis permintaan.

CREATE TABLE #DelTest (ID INT IDENTITY, name NVARCHAR(128)); -- Build the test table
INSERT INTO #DelTest (name) SELECT name FROM sys.objects;  -- fill from system DB
SELECT COUNT(*) TableNamesContainingSys FROM #deltest WHERE name LIKE '%sys%'; -- check rowcount
go
DECLARE @HowMany INT;
DECLARE @RowsTouched INT;
DECLARE @TotalRowCount INT;
DECLARE @msg VARCHAR(100);
DECLARE @starttime DATETIME 
DECLARE @currenttime DATETIME 

SET @RowsTouched = 1; -- Needs to be >0 for loop to start
SET @TotalRowCount=0  -- Total rows deleted so far is 0
SET @HowMany = 5;     -- Variable to choose how many rows to delete per loop
SET @starttime=GETDATE()

WHILE @RowsTouched > 0
BEGIN
   DELETE TOP (@HowMany)
   FROM #DelTest 
   WHERE name LIKE '%sys%';

   SET @RowsTouched = @@ROWCOUNT; -- Rows deleted this loop
   SET @TotalRowCount = @[email protected]; -- Increment Total rows deleted count
   SET @currenttime = GETDATE();
   SELECT @msg='Deleted ' + CONVERT(VARCHAR(9),@TotalRowCount) + ' Records. Runtime so far is '+CONVERT(VARCHAR(30),DATEDIFF(MILLISECOND,@starttime,@currenttime))+' milliseconds.'
   RAISERROR(@msg, 0, 1) WITH NOWAIT;  -- Print message after every loop. Can't use the PRINT function as SQL buffers output in loops.  

END; 
SELECT COUNT(*) TableNamesContainingSys FROM #DelTest WHERE name LIKE '%sys%'; -- Check row count after loop finish
DROP TABLE #DelTest;
1
Max xaM