Memperbarui tabel dengan jutaan catatan, sudah 4 hari

12

Saat ini saya memperbarui tabel dengan jutaan catatan, sudah 4 hari dan permintaan masih berjalan.

Saya memeriksa monitor aktivitas yang menunjukkan bahwa kueri sedang berjalan.

Dalam log peristiwa tidak ada kesalahan sama sekali.

Kinerja bijaksana:

  • Tempdb dalam disk A (ruang bebas 850 gb)
  • file basis data dalam disk B (ruang kosong 750 gb)
  • Ram 16 GB

Tolong sarankan saya apa yang harus saya lakukan?

Kueri

UPDATE
    dbo.table1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
    dbo.table2 t2
WHERE
    LEFT(dbo.test1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 
Beruntung
sumber

Jawaban:

3

Ada detail menarik untuk kueri ini yang awalnya tidak saya temukan. Berkat jawaban Fabricio Araujo sekarang saya melihatnya: Anda mengakses dua tabel. Saya belum pernah melihat penggunaan pernyataan pembaruan seperti ini sebelumnya dan saya tidak menyarankan untuk menggunakannya. Saya sarankan Anda menggunakan sintaks bergabung yang lebih intuitif per jawaban Fabricio.

Kemungkinan penyebabnya adalah bahwa gabungan antara dua tabel menghasilkan jumlah baris yang ekstrim. Ini mungkin terjadi jika LEFT(col, 3)ekspresi menghasilkan nilai duplikat. Jika menghasilkan 10 duplikat, ini akan menghasilkan 100000x100000 = 10000000000 baris di hasil gabungan.

Saya tidak berpikir bahwa pengindeksan berperan di sini. SQL Server dapat menyelesaikan gabung tanpa indeks ini baik-baik saja dengan hash atau gabungan gabung. Tidak butuh 4 hari.

Penyebab lainnya mungkin adalah kardinalitas yang meremehkan input atau output gabungan. SQL Server mungkin telah memilih loop bergabung.

Karena ini masih spekulasi, saya sarankan Anda mengirim rencana kueri yang akan menjelaskan masalah ini.

usr
sumber
8

Kueri ini mengharuskan Anda untuk memindai setiap baris dalam tabel karena

  • Saya kira procodet atau ProviderCode tidak diindeks
  • Bahkan jika mereka diindeks, Anda memiliki KIRI yang merupakan fungsi pada predikat WHERE
  • Dan Anda memiliki COLLATE juga yang secara efektif berfungsi pada predikat WHERE

"fungsi pada predikat WHERE" berarti indeks tidak akan digunakan

Jika Anda mengelompokkannya (katakan pada TOP UPDATE (10000) ... DAN costPercentage ADALAH NULL) maka Anda memerlukan indeks pada costPercentage dan ini mengasumsikan Anda sedang mengaturnya.

Satu-satunya solusi yang saya lihat adalah

  • mengisi tabel baru dalam batch, berdasarkan, katakanlah, kunci utama
  • buat indeks, kolom dihitung untuk menyembunyikan ekspresi LEFT dan COLLATE, lalu jalankan pembaruan
gbn
sumber
@ gbn .. terima kasih itu ide yang bagus .. tetapi karena data dalam jutaan proses ini akan memakan waktu .... saya berpikir mungkin ada cara untuk mengetahui kemajuan permintaan?
Lucky
1
Mengapa perlu 4 hari untuk memindai "jutaan" baris? Tidak peduli seberapa besar dan sangat terindeks baris mungkin, itu seharusnya tidak memakan waktu 4 hari. Akar masalahnya masih belum diketahui.
usr
1
Jika Anda secara teratur menangani data besar, bagaimana dengan Anda mendapatkan server yang tepat untuk itu? Letakkan data pada SSD dll.
TomTom
1
@ Beruntung tentu saja. Saya sedang menjawab jawabannya. Ada yang salah yang belum kami temukan. Ini bukan permintaan dengan sendirinya atau perangkat keras. Itu tidak akan pernah mencapai durasi 4 hari.
usr
3
Mengingat bahwa kueri bergabung dengan bagian 3 karakter dari kolom ke bagian 3 karakter dari kolom lain, hasilnya kemungkinan besar akan berisi duplikat. Ini jauh lebih buruk daripada hanya memperbarui jutaan baris. Saya yakin itu memindai melalui meja kerja di miliaran.
datagod
4

Pertama-tama, ubah kueri ke:

UPDATE t1
SET 
    costPercentage = ISNULL(t2.PaymentIndex, 1.0),
    t2.TopUp_Amt = (ISNULL(t2.PaymentIndex, 1.0) - 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00),
    Total_Tariff_Inc_t2 = ISNULL(t2.PaymentIndex, 1.0)
    * ISNULL(dbo.table1.Initial_Tariff_Amt, 0.00)
FROM
  dbo.table1 t1
  inner join dbo.table2 t2
    on LEFT(t1.procodet, 3) = LEFT(t2.ProviderCode, 3) COLLATE database_default 

Seperti yang ditunjukkan oleh posting pertama Jeff Moden dalam diskusi itu , permintaan Anda sangat mirip dengan yang ia ingatkan tentang "efek Halloween".

Setelah itu, ekspresi LEFT tersebut harus diindeks. Jawaban gbn memberi Anda petunjuk bagaimana melakukan itu.

Fabricio Araujo
sumber