È possibile che le istruzioni SQL vengano eseguite contemporaneamente all'interno di una singola sessione in SQL Server?


16

Ho scritto una procedura memorizzata che utilizza una tabella temporanea. So che in SQL Server le tabelle temporanee sono orientate alla sessione. Tuttavia, non sono stato in grado di trovare informazioni definitive su ciò di cui è capace una sessione. In particolare, se è possibile che questa procedura memorizzata venga eseguita due volte contemporaneamente in una singola sessione, è necessario un livello di isolamento significativamente più elevato per una transazione all'interno di quella procedura a causa delle due esecuzioni che ora condividono una tabella temporanea.

Risposte:


19

Mentre la risposta di Brent è corretta per tutti gli scopi pratici, e questo non è qualcosa di cui abbia mai visto qualcuno preoccuparsi, è possibile che più invocazioni di una procedura memorizzata in una sessione si influenzino a vicenda attraverso una tabella #temp nell'ambito della sessione .

La buona notizia è che è estremamente improbabile che accada in natura perché

1) # Le tabelle temporanee dichiarate all'interno di una stored procedure o di lotti nidificati in realtà non hanno visibilità della sessione (o durata). E questi sono di gran lunga il caso più comune.

2) Richiede MultipleActiveResultsets e una programmazione client asincrona molto strana, oppure la procedura memorizzata deve restituire un gruppo di risultati nel mezzo e il client deve chiamare un'altra istanza della procedura memorizzata mentre elabora i risultati dal primo.

Ecco un esempio inventato:

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

quali uscite

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

perché la seconda chiamata della procedura memorizzata ha inserito una riga, quindi ha eliminato tutte le righe da #t mentre la prima chiamata era in attesa che il client recuperasse le righe dal suo primo set di risultati. Si noti che se il primo set di risultati fosse piccolo, le righe potrebbero essere memorizzate nel buffer e l'esecuzione potrebbe continuare senza inviare nulla al client.

Se si sposta il

create table #t(id int)

nella procedura memorizzata genera:

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

E con la tabella temporanea dichiarata all'interno della procedura, se si cambia la seconda query in

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

Non riesce con:

'Nome oggetto non valido' #t '.'

Perché una tabella #temp creata all'interno di una stored procedure o di un batch nidificato è visibile solo in quella stored procedure o batch e nelle procedure e batch nidificati che chiama e viene distrutta al termine della procedura o del batch.


12

Non contemporaneamente. Le tue opzioni includono:

  • Esegui le query una dopo l'altra nella stessa sessione
  • Passa da una tabella temporanea a una tabella temporanea globale (usa ## TableName anziché #TableName), ma tieni presente che la tabella temporanea globale viene automaticamente eliminata quando si chiude la sessione che ha creato la tabella temporanea e non ci sono altre sessioni attive con un riferimento ad esso
  • Passa a una tabella utente reale in TempDB: puoi creare tabelle lì, ma tieni presente che scompariranno al riavvio del server
  • Passa a una tabella utenti reale in un database utenti
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.