J'ai écrit une procédure stockée qui utilise une table temporaire. Je sais que dans SQL Server, les tables temporaires ont une portée de session. Cependant, je n'ai pas pu trouver d'informations définitives sur ce dont une session est capable. En particulier, s'il est possible que cette procédure stockée s'exécute deux fois simultanément dans une même session, un niveau d'isolement nettement plus élevé est requis pour une transaction au sein de cette procédure car les deux exécutions partagent désormais une table temporaire.
Bien que la réponse de Brent soit correcte à toutes fins pratiques, et que je n'ai jamais vu quelqu'un s'inquiéter, cela est possible pour plusieurs invocations de une procédure stockée dans une session pour s'influencer mutuellement via une table #temp à portée de session.
La bonne nouvelle est qu'il est extrêmement improbable de se produire dans la nature car
1) Les tables #Temp déclarées à l'intérieur d'une procédure stockée ou de lots imbriqués n'ont pas réellement de visibilité de session (ou de durée de vie). Et ce sont de loin le cas le plus courant.
2) Il nécessite MultipleActiveResultsets et soit une programmation client asynchrone très étrange, soit que la procédure stockée renvoie un ensemble de résultats au milieu, et que le client appelle une autre instance de la procédure stockée lors du traitement des résultats à partir de la première.
Voici un exemple artificiel:
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();
}
}
}
qui sort
Numer of rows in temp table 0
Hit any key to exit
car le deuxième appel de la procédure stockée a inséré une ligne, puis supprimé toutes les lignes de #t pendant que le premier appel attendait que le client récupère les lignes de son premier jeu de résultats. Notez que si le premier ensemble de résultats était petit, les lignes pourraient être mises en mémoire tampon et l'exécution pourrait continuer sans rien envoyer au client.
Si vous déplacez le
create table #t(id int)
dans la procédure stockée, il génère:
Numer of rows in temp table 1
Hit any key to exit
Et avec la table temporaire déclarée à l'intérieur de la procédure, si vous changez la deuxième requête en
cmd2.CommandText = "select * from #t";
Il échoue avec:
'Nom d'objet non valide' #t '.'
Parce qu'une table #temp créée à l'intérieur d'une procédure stockée ou d'un lot imbriqué n'est visible que dans cette procédure stockée ou ce lot et dans les procédures et les lots imbriqués qu'elle appelle et est détruite à la fin de la procédure ou du lot.
Pas simultanément. Vos options comprennent: