Mungkinkah pernyataan SQL dijalankan secara bersamaan dalam satu sesi di SQL Server?

16

Saya telah menulis prosedur tersimpan yang menggunakan tabel sementara. Saya tahu bahwa di SQL Server, tabel sementara dibatasi sesi. Namun, saya belum dapat menemukan informasi pasti tentang apa yang bisa dilakukan oleh sesi. Secara khusus, jika dimungkinkan untuk prosedur tersimpan ini untuk mengeksekusi dua kali secara bersamaan dalam satu sesi, tingkat isolasi yang jauh lebih tinggi diperlukan untuk transaksi dalam prosedur tersebut karena dua eksekusi sekarang berbagi tabel sementara.

Trevor Giddings
sumber

Jawaban:

19

Meskipun jawaban Brent benar untuk semua tujuan praktis, dan ini bukan sesuatu yang pernah saya lihat dikhawatirkan seseorang, adalah mungkin untuk beberapa doa dari prosedur tersimpan dalam sesi untuk saling mempengaruhi melalui tabel #temp yang dilingkari dengan sesi. .

Berita baiknya adalah itu sangat tidak mungkin terjadi di alam liar karena

1) Tabel #Temp dinyatakan dalam prosedur tersimpan atau kumpulan bersarang tidak benar-benar memiliki visibilitas sesi (atau seumur hidup). Dan ini adalah jauh kasus yang paling umum.

2) Memerlukan MultipleActiveResultsets dan beberapa pemrograman klien async yang sangat aneh, atau agar prosedur tersimpan mengembalikan hasil di tengah, dan klien untuk memanggil contoh lain dari prosedur tersimpan sambil memproses hasil dari yang pertama.

Inilah contoh yang dibuat-buat:

using System;
using System.Data.SqlClient;

namespace ado.nettest
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var con = new SqlConnection("Server=localhost;database=tempdb;integrated security=true;MultipleActiveResultSets = True"))
            {
                con.Open();

                var procDdl = @"
create table #t(id int)
exec ('
create procedure #foo
as
begin
  insert into #t(id) values (1);
  select top 10000 * from sys.messages m, sys.messages m2;
  select count(*) rc from #t;
  delete from #t;
end
');
";
                var cmdDDL = con.CreateCommand();
                cmdDDL.CommandText = procDdl;
                cmdDDL.ExecuteNonQuery();

                var cmd = con.CreateCommand();
                cmd.CommandText = "exec #foo";
                using (var rdr = cmd.ExecuteReader())
                {
                    rdr.Read();

                    var cmd2 = con.CreateCommand();
                    cmd2.CommandText = "exec #foo";
                    using (var rdr2 = cmd2.ExecuteReader())
                    {

                    }

                    while (rdr.Read())
                    {

                    }
                    rdr.NextResult();
                    rdr.Read();
                    var rc = rdr.GetInt32(0);
                    Console.WriteLine($"Numer of rows in temp table {rc}");

                }


            }

            Console.WriteLine("Hit any key to exit");
            Console.ReadKey();
        }
    }
}

output yang mana

Numer of rows in temp table 0
Hit any key to exit

karena doa kedua dari prosedur tersimpan memasukkan satu baris, dan kemudian menghapus semua baris dari #t sementara doa pertama sedang menunggu klien untuk mengambil baris dari resultset pertamanya. Perhatikan bahwa jika resultset pertama kecil, baris mungkin mendapat buffered dan eksekusi dapat berlanjut tanpa mengirim apa pun ke klien.

Jika Anda memindahkan

create table #t(id int)

ke dalam prosedur tersimpan itu dihasilkan:

Numer of rows in temp table 1
Hit any key to exit

Dan dengan tabel temp dideklarasikan di dalam prosedur, jika Anda mengubah kueri kedua menjadi

cmd2.CommandText = "select * from #t";

Gagal dengan:

'Nama objek tidak valid' #t '.'

Karena tabel #temp dibuat di dalam prosedur tersimpan atau kumpulan bersarang hanya terlihat dalam prosedur tersimpan atau kumpulan dan dalam prosedur bersarang dan kumpulan yang dipanggil, dan dihancurkan ketika prosedur atau kumpulan berakhir.

David Browne - Microsoft
sumber
12

Tidak bersamaan. Pilihan Anda meliputi:

  • Jalankan kueri satu demi satu di sesi yang sama
  • Beralih dari tabel temp ke tabel temp global (gunakan ## TableName alih-alih #TableName), tetapi perlu diketahui bahwa tabel temp global secara otomatis dibatalkan ketika sesi yang membuat tabel temp ditutup, dan tidak ada sesi aktif lainnya dengan referensi untuk itu
  • Beralih ke tabel pengguna nyata di TempDB - Anda bisa membuat tabel di sana, tetapi perlu diketahui bahwa tabel itu akan hilang saat server restart
  • Beralih ke tabel pengguna nyata di basis data pengguna
Brent Ozar
sumber