Saya memiliki pernyataan SQL UPDATE dengan klausa "TOP (X)", dan baris yang saya perbarui nilainya memiliki sekitar 4 miliar baris. Ketika saya menggunakan "TOP (10)", saya mendapatkan satu paket eksekusi yang dieksekusi hampir secara instan, tetapi ketika saya menggunakan "TOP (50)" atau lebih besar, kueri tidak pernah (setidaknya, tidak saat saya menunggu) selesai, dan menggunakan rencana eksekusi yang sama sekali berbeda. Kueri yang lebih kecil menggunakan paket yang sangat sederhana dengan sepasang indeks pencarian dan loop bersarang bergabung, di mana kueri yang sama persis (dengan jumlah baris yang berbeda dalam klausa TOP dari pernyataan UPDATE) menggunakan rencana yang melibatkan dua pencarian indeks yang berbeda , gulungan meja, paralelisme, dan banyak kerumitan lainnya.
Saya telah menggunakan "OPTION (USE PLAN ...)" untuk memaksanya menggunakan rencana eksekusi yang dihasilkan oleh kueri yang lebih kecil - ketika saya melakukan ini, saya dapat memperbarui sebanyak 100.000 baris dalam beberapa detik. Saya tahu rencana kueri itu baik, tetapi SQL Server hanya akan memilih paket itu sendiri ketika hanya sejumlah kecil baris yang terlibat - setiap jumlah baris yang lumayan besar dalam pembaruan saya akan menghasilkan rencana sub-optimal.
Saya pikir mungkin paralelisme yang harus disalahkan, jadi saya menetapkan MAXDOP 1
permintaan, tetapi tidak berpengaruh - langkah itu hilang, tetapi pilihan / kinerja yang buruk tidak. Saya juga berlari sp_updatestats
pagi ini untuk memastikan itu bukan penyebabnya.
Saya telah melampirkan dua paket eksekusi - yang lebih pendek juga lebih cepat. Selain itu, inilah pertanyaan dalam pertanyaan (perlu dicatat bahwa SELECT yang saya sertakan tampaknya cepat dalam kasus jumlah baris kecil dan besar):
update top (10000) FactSubscriberUsage3
set AccountID = sma.CustomerID
--select top 50 f.AccountID, sma.CustomerID
from FactSubscriberUsage3 f
join dimTime t
on f.TimeID = t.TimeID
join #mac sma
on f.macid = sma.macid
and t.TimeValue between sma.StartDate and sma.enddate
where f.AccountID = 0 --There's a filtered index on the table for this
Dan inilah yang lebih lambat :
Apakah ada sesuatu yang jelas baik dalam cara saya mengatur permintaan saya atau dalam rencana pelaksanaan asalkan akan meminjamkan diri ke pilihan yang buruk mesin query membuat? Jika perlu, saya juga bisa memasukkan definisi tabel yang terlibat dan indeks yang ditentukan pada mereka.
Bagi mereka yang meminta versi hanya objek statistik dari database: Saya bahkan tidak menyadari Anda bisa melakukan itu, tetapi itu masuk akal! Saya mencoba membuat skrip untuk database hanya statistik sehingga orang lain dapat menguji rencana eksekusi untuk diri mereka sendiri, tetapi saya dapat menghasilkan statistik / histogram pada indeks saya yang difilter (tampaknya kesalahan sintaksis dalam skrip), jadi saya kurang beruntung di sana. Saya mencoba menghapus filter dan rencana kueri sudah dekat, tetapi tidak persis sama, dan saya tidak ingin mengirim siapa pun yang mengejar angsa.
Perbarui dan beberapa rencana eksekusi yang lebih lengkap: Pertama, Rencana Penjelajah SQL Sentry adalah alat yang luar biasa. Saya bahkan tidak tahu itu ada sampai melihat pertanyaan rencana kueri lainnya di situs ini, dan ada sedikit yang bisa dikatakan tentang bagaimana permintaan saya dieksekusi. Meskipun saya tidak yakin bagaimana cara mengatasi masalah tersebut, mereka memperjelas apa masalahnya.
Inilah ringkasan untuk 10, 100, dan 1000 baris - Anda dapat melihat bahwa kueri 1000 baris adalah jalan, jauh dari yang lain:
Anda dapat melihat bahwa kueri ketiga memiliki jumlah pembacaan yang konyol, sehingga jelas melakukan sesuatu yang sangat berbeda. Berikut perkiraan rencana eksekusi, dengan jumlah baris. Perkiraan rencana eksekusi 1000-baris:
Dan inilah hasil aktual dari rencana eksekusi (omong-omong, dengan "tidak pernah selesai", ternyata yang saya maksudkan adalah "selesai dalam satu jam"). Rencana pelaksanaan aktual 1000-baris
Hal pertama yang saya perhatikan adalah bahwa, alih-alih menarik 60k baris dari tabel dimTime seperti itu mengharapkan, itu sebenarnya menarik 1,6 miliar, dengan B . Melihat permintaan saya, saya tidak yakin bagaimana ini menarik kembali banyak baris dari tabel dimTime. Operator ANTARA yang saya gunakan hanya memastikan bahwa saya menarik catatan yang benar dari #mac berdasarkan catatan waktu pada tabel Fakta. Namun, ketika saya menambahkan baris ke klausa WHERE tempat saya memfilter t.TimeValue (atau t.TimeID) ke nilai tunggal, saya berhasil memperbarui 100.000 baris dalam hitungan detik. Sebagai akibatnya, dan sebagaimana dijelaskan dalam rencana eksekusi yang saya sertakan, sudah jelas bahwa tabel waktu saya adalah masalahnya, tetapi saya tidak yakin bagaimana saya akan mengubah kriteria bergabung untuk mengatasi masalah ini dan menjaga akurasi. . Adakah pikiran?
Untuk referensi, berikut paket (dengan jumlah baris) untuk pembaruan 100 baris. Anda dapat melihat bahwa itu menyentuh indeks yang sama, dan masih dengan satu ton baris, tetapi tidak jauh dari masalah yang sama. Eksekusi 100 baris dengan jumlah baris :
from #mac sma join f on f.macid = sma.macid join dimTime t on f.TimeID = t.TimeID and t.TimeValue between sma.StartDate and sma.enddate
vsfrom #mac join t on t.TimeValue between sma.StartDate and sma.enddate join f on f.TimeID = t.TimeID and f.macid = sma.macid
TOP 50
harus tetap mengeksekusi dengan cepat. Bisakah Anda mengunggah paket XML? Saya perlu melihat jumlah baris. Bisakah Anda menjalankan TOP 50
dengan maxdop 1 dan sebagai pilih, bukan sebagai pembaruan dan memposting rencana? (Mencoba menyederhanakan / membagi dua ruang pencarian).
t.TimeValue between sma.StartDate and sma.enddate
mungkin berakhir menghasilkan lebih banyak baris yang tidak berguna yang kemudian disaring dalam bergabung dengan FactSubscriber dan jadi tidak berakhir pada hasil akhir.
sp_updatestatistics
di atas meja?