SQL 语句是否可以在 SQL Server 的单个会话中同时执行?

Tre*_*ngs 16 sql-server sql-server-2012

我编写了一个使用临时表的存储过程。我知道在 SQL Server 中,临时表是会话范围的。但是,我无法找到有关会话确切功能的确切信息。特别是,如果此存储过程可以在单个会话中并发执行两次,则该过程中的事务需要显着更高的隔离级别,因为这两个执行现在共享一个临时表。

Dav*_*oft 19

而布伦特的答案是对所有的实际目的是正确的,这是不是我见过某人担心,这可以在会话存储过程中的多次调用通过会话范围#TEMP表互相影响.

好消息是这不可能发生在野外,因为

1) 在存储过程或嵌套批处理中声明的#Temp 表实际上没有会话可见性(或生命周期)。这些是迄今为止最常见的情况。

2)它需要MultipleActiveResultsets和一些非常奇怪的异步客户端编程,或者存储过程在中间返回一个结果集,客户端在处理第一个结果时调用存储过程的另一个实例。

这是一个人为的例子:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

哪个输出

Numer of rows in temp table 0
Hit any key to exit
Run Code Online (Sandbox Code Playgroud)

因为存储过程的第二次调用插入了一行,然后从#t 中删除了所有行,而第一次调用正在等待客户端从其第一个结果集中获取行。请注意,如果第一个结果集很小,则行可能会被缓冲并且可以继续执行而不向客户端发送任何内容。

如果你移动

create table #t(id int)
Run Code Online (Sandbox Code Playgroud)

进入它输出的存储过程:

Numer of rows in temp table 1
Hit any key to exit
Run Code Online (Sandbox Code Playgroud)

并与临时表声明的程序,如果你改变了第二次查询

cmd2.CommandText = "select * from #t";
Run Code Online (Sandbox Code Playgroud)

它失败了:

'无效的对象名称'#t'。'

因为在存储过程或嵌套批处理中创建的 #temp 表仅在该存储过程或批处理以及它调用的嵌套过程和批处理中可见,并且在过程或批处理结束时被销毁。


Bre*_*zar 12

不能同时进行。您的选择包括:

  • 在同一个会话中一个接一个地运行查询
  • 从临时表切换到全局临时表(使用 ##TableName 而不是 #TableName),但请注意,当创建临时表的会话关闭时,全局临时表会自动删除,并且没有其他活动会话与对它的引用
  • 切换到 TempDB 中的真实用户表 - 您可以在那里创建表,但请注意它们会在服务器重启时消失
  • 切换到用户数据库中的真实用户表