Apa yang lebih baik untuk perubahan besar pada tabel: HAPUS dan INSERT setiap kali atau PEMBARUAN yang ada?

27

Saya membuat proyek di mana saya perlu mengubah sekitar 36K catatan dalam satu tabel setiap hari. Saya bertanya-tanya apa yang akan tampil lebih baik:

  1. hapus baris dan masukkan yang baru, atau
  2. perbarui baris yang sudah ada

Bagi saya lebih mudah untuk hanya menghapus semua baris dan menyisipkan yang baru, tetapi jika ini akan memecah tabel dan indeks dan kinerja dampak maka saya lebih suka untuk membuat pembaruan di mana mungkin dan menghapus / menyisipkan hanya jika diperlukan.

Ini akan menjadi layanan malam dan saya tidak mencari untuk meningkatkan kecepatan proses itu sendiri. Saya lebih khawatir tentang kinerja kueri terhadap tabel ini secara umum di mana saya sudah memiliki 89 juta catatan dan bagaimana proses malam ini akan memengaruhinya.

Haruskah saya menghapus / menyisipkan catatan atau haruskah saya memperbarui yang sudah ada (jika memungkinkan) untuk proses malam ini?

adopilot
sumber
Saya percaya Anda harus memberikan rincian lebih lanjut di meja Anda, karena saya kira itu akan tergantung pada potensi keberadaan indeks di bidang.
SRKX

Jawaban:

9

Itu benar-benar tergantung pada seberapa banyak data berubah. Katakanlah tabel ini memiliki 20 kolom. Dan Anda juga memiliki 5 indeks - masing-masing pada diff. kolom.

Sekarang jika nilai dalam semua 20 kolom berubah ATAU bahkan jika data dalam 5 kolom berubah dan 5 kolom ini semuanya diindeks, maka Anda mungkin lebih baik "menghapus dan memasukkan". Tetapi jika hanya 2 kolom yang berubah dan katakanlah ini bukan bagian dari indeks yang tidak berkerumun, maka Anda mungkin lebih baik "Memutakhirkan" catatan karena dalam kasus ini hanya indeks yang dikelompokkan akan diperbarui (dan indeks tidak harus diperbarui).


Pada penelitian lebih lanjut, saya memang menemukan bahwa komentar di atas oleh saya agak berlebihan karena SQL Server secara internal memiliki 2 mekanisme terpisah untuk melakukan UPDATE. - "Pembaruan di tempat" (yaitu dengan mengubah nilai kolom menjadi yang baru di baris asli) atau sebagai "PEMBARUAN tidak di tempat" (HAPUS diikuti oleh INSERT).

Pembaruan di tempat adalah aturan dan dilakukan jika memungkinkan. Di sini baris tetap persis di lokasi yang sama pada halaman yang sama pada tingkat yang sama. Hanya byte yang terpengaruh yang dipilih. Tlog hanya memiliki satu catatan (asalkan tidak ada pemicu pembaruan). Pembaruan terjadi di tempat jika tumpukan sedang diperbarui (dan ada cukup ruang di halaman). Pembaruan juga terjadi jika kunci pengelompokan berubah tetapi baris tidak perlu bergerak sama sekali.

Misalnya: jika Anda memiliki indeks berkerumun di nama belakang dan Anda memiliki nama: Able, Baker, Charlie Sekarang Anda ingin memperbarui Baker ke Becker. Tidak ada baris yang harus dipindahkan. Jadi ini bisa terjadi. Sedangkan, jika Anda harus memperbarui Mampu ke Kumar, baris harus bergeser (meskipun mereka akan berada di halaman yang sama). Dalam hal ini, SQL Server akan melakukan DELETE diikuti oleh INSERT.

Mempertimbangkan hal di atas, saya akan menyarankan Anda melakukan UPDATE normal dan membiarkan SQL Server mencari cara terbaik untuk melakukannya secara internal.

Untuk detail lebih lanjut tentang internal "PEMBARUAN" atau yang terkait dengan SQL Server terkait, periksa buku Kalen Delaney, Paul Randal, dan lain-lain - SQL Server 2008 Internals .

Dharmendar Kumar 'DK'
sumber
8

Sudahkah Anda menyelidiki perintah MERGE dalam SQL 2008? Ini adalah contoh dasarnya:

  merge YourBigTable ybt
  using (select distinct (RecordID) from YourOtherTable) yot
     on yot.Recordid = YBT.RecordID
  when NOT matched by target
  then  insert (RecordID)
        values (yot.DeviceID) ;

Ini pada dasarnya adalah perintah "UPSERT". Perbarui jika ada, masukkan jika tidak. Perintah yang SANGAT cepat, sangat keren.

datagod
sumber
1
Itu tidak lebih cepat dari UPDATE, mekanik yang sama di bawah tenda.
Mark Storey-Smith
Ini lebih cepat daripada memperbarui lalu memasukkan yang belum ada.
datagod
2
Jika Anda tahu itu masalahnya, buktikan :)
Mark Storey-Smith
4

Tapi, saya sendiri memeriksa Hapus dan Sisipkan Pembaruan pada tabel yang memiliki catatan 30 juta (3 crore). Tabel ini memiliki satu kunci komposit unik berkerumun dan 3 kunci tidak tercakup. Untuk Hapus & Sisipkan, butuh 9 menit. Untuk Pembaruan butuh 55 menit. Hanya ada satu kolom yang diperbarui di setiap baris.

Jadi, saya meminta Anda untuk tidak menebak. Persamaan akan berubah ketika berhadapan dengan tabel besar dengan banyak kolom dan dengan banyak data.

srinivas
sumber
Saya juga menemukan kasus ini tetapi kemudian menemukan bahwa kadang-kadang dimungkinkan untuk mengoptimalkan penggabungan besar dengan menambahkan indeks (temp atau perm) ke sumber atau target, petunjuk, atau sub-pengaturan target (tidak berlaku untuk penggabungan penuh).
crokusek
3

Pembaruan tidak secepat. Caranya adalah dengan mencapai insert cepat adalah dengan menonaktifkan indeks saat data sedang dimasukkan.

Pertimbangkan untuk menggunakan ini:

-- disable indexes
ALTER INDEX [index_name] ON dbo.import_table DISABLE
-- ... disable more indexes

-- don't use delete if you don't care about minimal logging. truncate is faster
TRUNCATE TABLE dbo.import_table

-- just insert the new rows
INSERT dbo.import_table
SELECT
    *
FROM
    dbo.source_table

-- rebuild indexes
ALTER INDEX [index_name] ON dbo.import_table REBUILD
-- ... rebuild more indexes

Yang lebih cepat adalah juga mematikan pembaruan statistik otomatis dalam opsi db. Jika tabel berubah secara signifikan, Anda harus menjalankan:

UPDATE STATISTICS dbo.import_table

atau

EXEC sp_updatestats

sebagai pekerjaan secara teratur (harian, mingguan tergantung pada ukuran db) untuk menjaga statistik tetap terbaru. Satu hal yang harus diwaspadai adalah memperbarui statistik ketika tabel kosong. Itu akan mengacaukan statistik jika Anda tidak menjalankannya setelah tabel diisi kembali.

Asken
sumber
4
Saya tidak setuju bahwa ini selalu terjadi. Juga, tabel dalam pertanyaan @ adopilot tidak dapat dihapus oleh TRUNCATE karena berisi 89m catatan dan dia ingin memperbarui hanya 36rb.
Mark Storey-Smith
perlu belajar membaca posting lebih hati-hati! saya akan memperbarui pos ... sebenarnya, saya perlu banyak berubah.
Asken