Saya perlu mengembalikan hasil sebagian (sesederhana pilih) dari prosedur Disimpan sebelum selesai.
Apakah mungkin untuk melakukan itu?
Jika ya, bagaimana cara melakukannya?
Jika tidak, ada solusi?
EDIT: Saya punya beberapa bagian dari prosedur. Pada bagian pertama saya menghitung beberapa string. Saya menggunakannya nanti dalam prosedur untuk membuat operasi tambahan. Masalahnya adalah bahwa string dibutuhkan oleh penelepon sesegera mungkin. Jadi saya perlu menghitung string itu dan meneruskannya kembali (entah bagaimana, dari pilih misalnya) dan kemudian terus bekerja. Penelepon mendapatkan string berharga jauh lebih cepat.
Penelepon adalah Layanan Web.
sql-server-2012
t-sql
stored-procedures
multi-thread
web-service
Bogdan Bogdanov
sumber
sumber
Jawaban:
Anda mungkin mencari
RAISERROR
perintah denganNOWAIT
opsi.Per sambutan :
Ini tidak mengembalikan hasil dari
SELECT
pernyataan, tetapi itu akan membiarkan Anda meneruskan pesan / string kembali ke klien. Jika Anda ingin mengembalikan subset cepat dari data yang Anda pilih maka Anda mungkin ingin mempertimbangkanFAST
petunjuk kueri.Ditambahkan oleh Shannon Severance dalam komentar:
Dari Penanganan Kesalahan dan Transaksi di SQL Server oleh Erland Sommarskog:
Lihat artikel sumber untuk konteks penuh.
sumber
FAST
memecahkan masalah bagi saya dalam masalah di mana saya perlu menyinkronkan pelaksanaan prosedur tersimpan dan kode C # untuk memperburuk dan mereproduksi kondisi balapan. Lebih mudah untuk mengkonsumsi hasil secara terprogram daripada menggunakan sesuatu sepertiRAISERROR()
. Ketika saya mulai membaca jawaban Anda, sepertinya Anda mengatakan bahwa itu tidak dapat dilakukanSELECT
, jadi mungkin itu bisa diklarifikasi?UPDATE: Lihat jawaban strutzky (di atas ) dan komentar untuk setidaknya satu contoh di mana ini tidak berperilaku seperti yang saya harapkan dan jelaskan di sini. Saya harus bereksperimen / membaca lebih lanjut untuk memperbarui pemahaman saya ketika waktu mengizinkan ...
Jika pemanggil Anda berinteraksi dengan basis data secara tidak sinkron atau berulir / multi-proses, sehingga Anda dapat membuka sesi kedua saat sesi pertama masih berjalan, Anda bisa membuat tabel untuk menampung sebagian data dan memutakhirkannya seiring prosedur berlangsung. Ini kemudian dapat dibaca oleh sesi kedua dengan tingkat isolasi 1 set transaksi untuk memungkinkannya membaca perubahan yang tidak dikomit:
1: sesuai komentar dan pembaruan berikutnya dalam jawaban srutzky, pengaturan tingkat isolasi tidak diperlukan jika proses yang dipantau tidak dibungkus dalam transaksi, meskipun saya cenderung menetapkannya karena kebiasaan dalam keadaan seperti itu karena tidak menyebabkan membahayakan saat tidak diperlukan dalam kasus ini
Tentu saja jika Anda dapat memiliki beberapa proses yang beroperasi dengan cara ini (yang kemungkinan jika server web Anda menerima pengguna secara bersamaan dan sangat jarang hal itu tidak terjadi) Anda harus mengidentifikasi informasi kemajuan untuk proses ini dengan cara tertentu . Mungkin lulus prosedur UUID yang baru dicetak sebagai kunci, tambahkan itu ke tabel progres, dan bacalah dengan:
Saya telah menggunakan metode ini untuk memantau proses manual yang berjalan lama di SSMS. Saya tidak dapat memutuskan apakah itu "bau" terlalu banyak bagi saya untuk mempertimbangkan menggunakannya dalam produksi meskipun ...
sumber
OP telah mencoba mengirim beberapa set hasil (bukan MARS) dan telah melihat bahwa memang menunggu Prosedur Tersimpan untuk menyelesaikan sebelum mengembalikan set hasil apa pun. Dengan mengingat situasi itu, berikut adalah beberapa opsi:
Jika data Anda cukup kecil untuk ditampung dalam 128 byte, kemungkinan besar Anda bisa menggunakan
SET CONTEXT_INFO
yang seharusnya membuat nilai itu terlihatSELECT [context_info] FROM [sys].[dm_exec_requests] WHERE [session_id] = @SessionID;
. Anda hanya perlu menjalankan kueri cepat sebelum menjalankan Prosedur TersimpanSELECT @@SPID;
dan mengambilnyaSqlCommand.ExecuteScalar
.Saya baru saja menguji ini dan itu berhasil.
Mirip dengan saran @ David untuk menempatkan data ke dalam tabel "progres", tetapi tanpa perlu dipusingkan dengan masalah pembersihan atau konkurensi / pemisahan proses:
Guid
di dalam kode aplikasi dan berikan sebagai parameter ke Prosedur Tersimpan. Simpan Panduan ini dalam sebuah variabel karena akan digunakan beberapa kali.CREATE TABLE ##MyProcess_{GuidFromApp};
. Tabel dapat memiliki kolom apa pun dari tipe data apa pun yang Anda butuhkan.Kapan pun Anda memiliki data, masukkan ke dalam Tabel Temp Global itu.
Dalam kode aplikasi, mulai mencoba untuk membaca data, tetapi membungkus
SELECT
dalamIF EXISTS
sehingga tidak akan gagal jika tabel belum dibuat belum:Dengan
String.Format()
, Anda bisa mengganti{0}
dengan nilai dalam variabel Guid. Uji apakahReader.HasRows
, dan jika benar maka bacalah hasilnya, panggil lagiThread.Sleep()
atau apa saja untuk kemudian polling lagi.Manfaat:
EXEC
/sp_executesql
panggilan)Saya telah menguji ini dan berfungsi seperti yang diharapkan. Anda dapat mencobanya sendiri dengan contoh kode berikut.
Di satu tab permintaan, jalankan yang berikut, dan kemudian sorot 3 baris di blok-komentar dan jalankan itu:
Buka tab "Pesan" dan salin GUID yang dicetak. Kemudian, buka tab kueri lain dan jalankan yang berikut, letakkan GUID yang Anda salin dari tab Pesan Sesi lain ke inisialisasi variabel di baris 1:
Terus memukul F5. Anda akan melihat 1 entri untuk 10 detik pertama, dan kemudian 2 entri untuk 10 detik berikutnya.
Anda dapat menggunakan SQLCLR untuk melakukan panggilan kembali ke aplikasi Anda melalui Layanan Web atau cara lain.
Anda mungkin dapat menggunakan
PRINT
/RAISERROR(..., 1, 10) WITH NOWAIT
untuk mengirim string kembali dengan segera, tetapi ini akan sedikit rumit karena masalah berikut:VARCHAR(8000)
atauNVARCHAR(4000)
Pesan, secara default, juga tidak dikirim sampai proses selesai. Perilaku ini, bagaimanapun, dapat diubah dengan menyetel SqlConnection.FireInfoMessageEventOnUserErrors Property ke
true
. Dokumentasi menyatakan:Kelemahan di sini adalah bahwa sebagian besar kesalahan SQL tidak akan lagi meningkatkan
SqlException
. Dalam hal ini, Anda perlu menguji properti acara tambahan yang diteruskan ke Message Event Handler. Ini berlaku untuk seluruh koneksi, yang membuat segalanya sedikit rumit, tetapi tidak dapat dikelola.Semua pesan muncul di tingkat yang sama tanpa bidang atau properti terpisah untuk membedakan satu dari yang lain. Urutan penerimaannya harus sama dengan cara pengirimannya, tetapi tidak yakin apakah itu cukup dapat diandalkan. Anda mungkin perlu menyertakan tag atau sesuatu yang kemudian dapat Anda parsing. Dengan begitu Anda setidaknya bisa memastikan yang mana yang mana.
sumber
RETURN
pernyataan). Jadi tidak berfungsi.SqlConnection
? Berapa banyak data yang ingin Anda sampaikan kembali? Tipe data apa? Sudahkah Anda mencobaPRINT
atau tidakRAISERROR WITH NOWAIT
?Jika prosedur tersimpan Anda perlu dijalankan di latar belakang (mis. Tidak serempak), maka Anda harus menggunakan Pialang Layanan. Agak sulit untuk diatur, tetapi setelah selesai, Anda akan dapat memulai prosedur yang tersimpan (non-pemblokiran) dan mendengarkan pesan kemajuan selama (atau sesedikit) yang Anda inginkan.
sumber