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


16

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

Answers:


19

尽管Brent的回答对于所有实际目的都是正确的,这不是我见过的人担心的事情,但会话中存储过程的多次调用可能通过会话范围的#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();
        }
    }
}

哪个输出

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

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

如果您移动

create table #t(id int)

输出到存储过程中:

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

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

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

它失败并显示:

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

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


12

不能同时使用。您的选择包括:

  • 在同一会话中一个接一个地运行查询
  • 从临时表切换到全局临时表(使用## TableName代替#TableName),但是要注意,当创建临时表的会话关闭时,全局临时表会自动删除,并且没有其他活动会话对它的引用
  • 切换到TempDB中的真实用户表-您可以在其中创建表,但是请注意,它们将在服务器重启时消失
  • 切换到用户数据库中的真实用户表
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.