it-swarm.com.de

Können SQL-Anweisungen in einer einzelnen Sitzung in SQL Server gleichzeitig ausgeführt werden?

Ich habe eine gespeicherte Prozedur geschrieben, die eine temporäre Tabelle verwendet. Ich weiß, dass temporäre Tabellen in SQL Server einen Sitzungsbereich haben. Ich konnte jedoch keine endgültigen Informationen darüber finden, wozu eine Sitzung in der Lage ist. Insbesondere wenn es möglich ist, dass diese gespeicherte Prozedur zweimal gleichzeitig in einer einzelnen Sitzung ausgeführt wird, ist für eine Transaktion innerhalb dieser Prozedur eine erheblich höhere Isolationsstufe erforderlich, da die beiden Ausführungen jetzt eine temporäre Tabelle gemeinsam nutzen.

16
Trevor Giddings

Während Brents Antwort für alle praktischen Zwecke korrekt ist und ich noch nie jemanden gesehen habe, der sich Sorgen macht, ist sie ist für mehrere Aufrufe einer gespeicherten Prozedur in einer Sitzung möglich sich gegenseitig durch eine sitzungsbezogene # temp-Tabelle zu beeinflussen.

Die gute Nachricht ist, dass es extrem unwahrscheinlich ist, dass es in freier Wildbahn passiert, weil

1) # Temp-Tabellen, die in gespeicherten Prozeduren oder verschachtelten Stapeln deklariert sind, haben keine Sitzungssichtbarkeit (oder Lebensdauer). Und dies sind bei weitem der häufigste Fall.

2) Es erfordert MultipleActiveResultsets und entweder eine sehr seltsame asynchrone Client-Programmierung oder, dass die gespeicherte Prozedur eine Ergebnismenge in der Mitte zurückgibt und der Client eine andere Instanz der gespeicherten Prozedur aufruft, während die Ergebnisse von verarbeitet werden Der Erste.

Hier ist ein erfundenes Beispiel:

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();
        }
    }
}

welche Ausgänge

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

weil beim zweiten Aufruf der gespeicherten Prozedur eine Zeile eingefügt und dann alle Zeilen aus #t gelöscht wurden, während der erste Aufruf darauf wartete, dass der Client die Zeilen aus seiner ersten Ergebnismenge abruft. Beachten Sie, dass bei einer kleinen ersten Ergebnismenge die Zeilen möglicherweise gepuffert werden und die Ausführung fortgesetzt werden kann, ohne dass etwas an den Client gesendet wird.

Wenn Sie die bewegen

create table #t(id int)

in die gespeicherte Prozedur gibt es aus:

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

Und mit der temporären Tabelle inside die Prozedur deklariert, wenn Sie die zweite Abfrage in ändern

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

Es schlägt fehl mit:

'Ungültiger Objektname' #t '.'

Weil eine # temp-Tabelle, die in einer gespeicherten Prozedur oder einem verschachtelten Stapel erstellt wurde, nur in dieser gespeicherten Prozedur oder diesem Stapel sowie in den von ihr aufgerufenen verschachtelten Prozeduren und Stapeln sichtbar ist und beim Beenden der Prozedur oder des Stapels zerstört wird.

Nicht gleichzeitig. Ihre Optionen umfassen:

  • Führen Sie die Abfragen nacheinander in derselben Sitzung aus
  • Wechseln Sie von einer temporären Tabelle zu einer globalen temporären Tabelle (verwenden Sie ## TableName anstelle von #TableName). Beachten Sie jedoch, dass die globale temporäre Tabelle automatisch gelöscht wird, wenn die Sitzung, die die temporäre Tabelle erstellt hat, geschlossen wird und keine anderen aktiven Sitzungen mit stattfinden ein Verweis darauf
  • Wechseln Sie in TempDB zu einer echten Benutzertabelle. Sie können dort Tabellen erstellen. Beachten Sie jedoch, dass diese beim Neustart des Servers verschwinden
  • Wechseln Sie zu einer realen Benutzertabelle in einer Benutzerdatenbank
12
Brent Ozar