Masalah saya (atau setidaknya pesan kesalahan) sangat mirip dengan prosesor kueri kehabisan sumber daya internal - kueri sql yang sangat panjang .
Pelanggan saya bekerja dengan kueri pemilihan-SQL, yang berisi klausa di mana dengan tepat 100.000 entri.
Permintaan gagal dengan kesalahan 8632 dan pesan kesalahan
Kesalahan internal: Batas layanan ekspresi telah tercapai. Harap cari kemungkinan ekspresi kompleks dalam kueri Anda, dan cobalah untuk menyederhanakannya.)
Saya merasa sangat aneh bahwa pesan kesalahan ini dilemparkan, tepat pada 100.000 entri, jadi saya ingin tahu apakah ini adalah nilai yang dapat dikonfigurasi. Apakah ini masalahnya dan dalam kasus ya, bagaimana saya bisa meningkatkan nilai ini ke yang lebih tinggi?
Di MSDN , ada proposal untuk menulis ulang kueri, tapi saya ingin menghindari ini.
Sementara itu saya telah menemukan bahwa daftar entri yang saya bicarakan berisi bilangan asli, beberapa dari mereka tampaknya berurutan (seperti (1,2,3,6,7,8,9,10,12, 13,15,16,17,18,19,20).
Ini membuat SQL di mana-klausa seperti:
where entry in (1,2,3,6,7,8,9,10,12,13,15,16,17,18,19,20)
Saya bisa mengubah ini menjadi:
where (entry between 1 and 3) OR
(entry between 6 and 10) OR
(entry between 12 and 13) OR
(entry between 15 and 20)
Bisakah ini disingkat dengan:
where entry in (1,...,3,6,...,10,12,13,15,...,20)
... atau yang serupa? (Saya tahu ini sangat sulit, tetapi itu akan membuat pembaruan perangkat lunak lebih mudah dan lebih mudah dibaca)
Untuk informasi Anda: data di mana-klausa adalah hasil perhitungan, dilakukan pada tabel lain: pertama entri tabel itu dibaca dan difilter di awal, kemudian beberapa pemrosesan tambahan dilakukan (yang tidak mungkin dilakukan dengan menggunakan SQL), hasil dari pemrosesan ekstra lebih banyak penyaringan dan hasil yang digunakan di mana-klausa. Karena tidak mungkin untuk menulis penyaringan lengkap dalam SQL, metode yang disebutkan telah digunakan. Tentunya isi dari mana-klausa mungkin berubah di setiap pemrosesan, karenanya kebutuhan solusi dinamis.
sumber
WHERE IN
tidak mendukung sintaks rentang semacam itu. Juga, seharusnyaWHERE () OR () OR ()
bukan DAN. Tetapi untuk menggunakan saran Brent, Anda sebenarnya tidak harus mengubah seluruh permintaan, Anda bisa melakukannyaWHERE IN (SELECT myID FROM #biglist)
. Dan#biglist
bisa berupa meja nyata (permanen), atau meja temp yang Anda buat dengan cepat.Jawaban:
Untuk mencari lebih dari 100.000 nilai, alih-alih masukkan dalam tabel temp, satu baris per nilai yang Anda cari. Kemudian, gabungkan kueri Anda ke tabel temp untuk filter
Sesuatu dengan lebih dari 100.000 nilai bukan parameter - ini adalah tabel. Daripada berpikir untuk menaikkan batas, pertimbangkan Aturan Sepuluh Persen dari Swart : jika Anda mendekati 10% dari batas SQL Server, Anda mungkin akan memiliki waktu yang buruk.
sumber
Jika Anda akan mengubah aplikasi, pertimbangkan juga
(a) menggunakan TVP untuk seluruh rangkaian nilai - Anda akan membuat
DataTable
dalam C # dan meneruskannya ke prosedur tersimpan menggunakanStructuredType
, seperti yang saya tunjukkan di sini . (Semoga 100.000 entri tidak normal, karena skalabilitas mungkin menjadi masalah apa pun pendekatan yang Anda gunakan.)atau
(B) menggunakan TVP untuk melewati batas atas dan bawah rentang, dan menulis gabungan yang sedikit berbeda (terima kasih @ ypercube).
sumber
Tidak, itu tidak dapat dikonfigurasi dan Anda tidak dapat meningkatkan ini ke yang lebih tinggi.
Ada solusi yang disarankan dalam artikel MSDN yang Anda sebutkan dan artikel lainnya. Saya sebutkan dua di sini tetapi Anda dapat mencari lebih banyak.
sumber
Hanya 2 ¢ saya tentang mempersingkat kondisi permintaan: -
Jika Anda dapat menentukan semua nilai yang mungkin ada
entry
di muka, apakah itu layak jika Anda mengambil pelengkap dari kueri Anda?Sebelum
Setelah
sumber
Sulit untuk mengetahui apa yang ingin Anda capai tanpa benar-benar dapat melihat kueri, tetapi di sini kita mulai, dengan asumsi bahwa kueri Anda hanya membutuhkan dua tabel, satu dengan data, satu dengan nilai-nilai yang ingin Anda hindari:
where entry in (<list of 100.000 values>)
sangat mengerikan, baik dari sudut pandang efisiensi maupun pemeliharaan.where entry in (select whatever from table)
sama mengerikannya dengan sebelumnya. Namun, tergantung pada kedua tabel keanehan dan mesin SQL, itu mungkin melakukan OK meskipun kanker kornea. (Mungkin OK di Oracle, tidak akan pernah di MySQL, tidak dapat mengingat tentang MSSQL).Menurut pendapat saya (tanpa mengetahui kueri sama sekali), Anda harus menulis ulang kueri sebagai berikut:
Jika 100.000 nilai itu selalu sama, tidak bergantung pada sisa kueri, Anda harus mengunggah nilai-nilai itu ke tabel (table_fixed_values), dan gunakan
Jika 100.000 nilai itu tidak sama, harus ada semacam logika untuk mengambil 100.000 nilai itu, logika yang harus Anda tanamkan dalam
ON
kueri sebelumnya.sumber
LEFT JOIN table_fixed_values ON A.entry=B.entry WHERE B.entry IS NOT NULL
dan tidak setara, lebih sederhana dan lebih mudah dibacaINNER JOIN table_fixed_values ON A.entry=B.entry
?