DIPERBARUI dengan BERGABUNG dengan catatan 100mm, bagaimana melakukan ini dengan lebih baik? (dalam T-SQL)

11

Saya perlu memperbarui 100 juta catatan dalam satu tabel, pada dasarnya, menormalkan tabel dengan mengganti nilai varchar dari sebuah kolom dengan hanya sebuah ID. (Saya mengatakan "mengganti" tetapi sebenarnya saya sedang menulis ID ke kolom lain.)

Apa yang saya coba capai adalah menormalkan dataset. Data yang belum dinormalisasi tidak memiliki indeks. Pikir saya adalah bahwa saya tidak akan membangun indeks pada nilai mentah, menunggu, alih-alih mengindeks kunci asing yang akan menggantikan nilai varchar dengan nilai tinyint setelah pembaruan selesai.

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

Latar Belakang

  • menggunakan MSSQL 2008 R2 pada Server 2008 R2
  • server memiliki RAM 8 GB
  • server memiliki satu RAID10, 7200 RPM SATA (tidak hebat, saya tahu, dalam produksi ini hanya akan membaca data dan tidak menulis data; ditambah kekurangan HD baru-baru ini membuat ini diperlukan untuk biaya)
  • server memiliki CPU Xeon quad-core ganda
  • mesin tidak melakukan hal lain (saat ini didedikasikan untuk dev, hanya proses ini)
  • logging sederhana dihidupkan (? - tetapi apakah itu masih masuk sehingga dapat mengembalikan?)
  • perhatikan bahwa kueri merujuk dua DB yang berbeda, untuk apa itu layak
  • "Lebar" dari catatan dalam tabel yang diperbarui adalah 455 byte

Sumber Daya Selama Eksekusi

  • RAM fisik sudah maksimal
  • disk I / O sudah maksimal
  • CPU hampir tidak melakukan apa-apa (choke point I / O)
  • jangka waktu telah 14 jam dan terus bertambah!

Saya menduga beberapa hal seperti saya perlu indeks pada data mentah, meskipun saya akan menjatuhkan kolom (AutoClassName) setelah pembaruan normalisasi. Saya juga bertanya-tanya apakah saya seharusnya hanya mengulang tabel satu per satu daripada BERSAMA, yang tampak konyol pada saat saya memulai ini, tetapi sekarang tampaknya itu akan lebih cepat.

Bagaimana saya harus mengubah metodologi saya untuk pembaruan normalisasi yang tersisa (mirip dengan yang ini) lebih cepat?

Chris Adragna
sumber

Jawaban:

7

Anda mencoba melakukan ini sebagai transaksi tunggal (sangat besar). Sebagai gantinya, lakukan pembaruan dalam batch yang lebih kecil.

Anda juga akan mendapat manfaat dari:

  • Indeks sementara pada AutoData.dbo.AutoClass.AutoClassName
  • RAM lebih banyak. RAM lebih banyak.
Mark Storey-Smith
sumber
1
+1 Saya setuju dengan pembaruan batch menggunakan TOPklausa. Itu akan menjadi pendekatan saya.
Thomas Stringer
Jika saya melakukan UPDATE TOP maka saya akan memerlukan klausa WHERE (WHERE AutoClassID NULL)? Bukankah klausa WHERE memperkenalkan hit kinerja baru (pemindaian tabel yang tidak saya lakukan sekarang). Tidak diragukan lagi itu akan mengurangi masalah RAM yang saya alami dengan GABUNG.
Chris Adragna
Respons saya sudah lama tertunda, tetapi dalam kasus saya, SET ROWCOUNT terbukti paling efektif.
Chris Adragna
10

Saya akan mengambil pendekatan yang berbeda.

Alih-alih memperbarui tabel yang sudah ada, cukup buat tabel baru yang memiliki apa yang Anda butuhkan.

Ini hampir pasti akan lebih cepat:

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

Seperti yang ditulis saat ini, ada banyak operasi logis yang terjadi:

  • Baca semua nilai A.AutoClassName
  • Baca semua nilai B.AutoClassName
  • Bandingkan nilai A dan B
  • Dari set yang cocok, baca semua nilai B.AutoClassID
  • Perbarui nilai A.AutoClassId yang sudah ada menjadi nilai B.AutoClassId melalui indeks apa pun yang ada
JNK
sumber
Ini kedengarannya seperti pendekatan yang bagus dan sederhana, terutama mengingat masalah I / O disk yang saya alami. Terima kasih telah menjawab begitu cepat.
Chris Adragna
1
Saya menyarankan Anda mengecek apakah Anda memiliki cukup ruang kosong di log dan file data. Jika file tumbuh secara otomatis, kinerja akan menurun. Saya sering melihat orang-orang menjalankan pembaruan besar, sekali saja dan mengembangkan secara otomatis file log mereka tanpa menyadarinya.
Selat darin
5

Melonggarkan meja satu baris sekaligus, tidak akan lebih cepat!

Seperti yang dicurigai, dan dikonfirmasi oleh Anda, ini akan terikat dengan I / o - memiliki satu disk, membaca, menulis, log transaksi, dan (apa saja) ruang kerja temp semua akan bersaing untuk i / o yang sama.

Pemulihan sederhana masih akan mencatat transaksi, tetapi log akan dihapus oleh pos pemeriksaan. Mungkin saja ukuran log awal Anda dan pengaturan pertumbuhan otomatis menyebabkan beberapa i / o melambat - log transaksi perlu tumbuh untuk mengakomodasi perubahan.

Sudahkah Anda mencoba mengindeks bidang AutoClassName? Berapa banyak nilai AutoClass yang berbeda?

Anda mungkin perlu mengelompokkan pembaruan, berdasarkan batasan i / o Anda. Jadi perbarui 1 juta, pos pemeriksaan, ulangi ....

Kev Riley
sumber
Hanya ada 15 nilai AutoClass yang berbeda. Komentar Anda mengkonfirmasi banyak kecurigaan saya (dan sakit!). Terima kasih telah menjawab.
Chris Adragna
3

Buat indeks untuk bidang yang bergabung.

Anda selalu dapat menjatuhkan indeks saat Anda selesai.

Saya akan sangat terkejut jika indeks tidak secara signifikan meningkatkan kinerja pembaruan.

Jimbo
sumber
Saya yakin indeks akan membaik. Saya kira pertanyaannya adalah apakah mereka meningkatkan lebih dari waktu yang diperlukan untuk membuat indeks (hanya untuk sekali pakai). Mungkin iya. :)
Chris Adragna
3

Ekspor seperti yang Anda inginkan, buat tabel baru dan impor kembali. Sebagai Bonus, Anda akan memiliki salinan data sebagai cadangan, jika keajaiban terjadi.

srini.venigalla
sumber