首页 > 解决方案 > SQL Server:如果我同时运行相同的存储过程,该存储过程具有对同一个临时表的选择,会发生什么情况

问题描述

任何想法,如果我同时运行相同的存储过程(使用 jmeter)会发生什么,并且在该存储过程中有查询

SELECT INTO #temp

第二个存储过程会在第一个存储过程完成后运行吗?

或者临时表会被创建两次(我听说 SQL Server 中有本地临时表)?

抱歉这个愚蠢的问题,我在谷歌上找不到任何答案。

谢谢

标签: sql-serverstored-procedurestemp-tables

解决方案


临时表仅存在于创建它的范围内(以及该范围的“子范围”),并且仅在该范围内持续存在。

所以,例如。如果您要运行以下内容,则不会出现任何错误:

EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int);';
EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int);';

这是因为该表#temp只存在于“动态”语句的范围内,并且一旦完成就会停止。

另一方面,类似下面的事情会失败(这是错误的,请参阅我在底部的编辑)

CREATE TABLE #temp (ID int);
EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int);';
DROP TABLE #temp;

那是因为“动态”语句可以访问“外部”范围,因此会看到它#temp已经存在并产生错误。

不可能在同一个连接中同时运行 2 个语句,因此您将无法同时调用同一个存储过程。这意味着两者都将具有不同的范围,因此将引用它们是自己的 object #temp,即特定于它们的范围。

你可以用类似的想法再次测试它。运行以下,然后打开一个新连接并再次运行它(在另一个完成之前)。你会注意到他们都成功了:

CREATE TABLE #temp (ID int);
WAITFOR DELAY '00:30'; --Waits 30 seconds
--While the WAITFOR happens, open the another connection and run all this SQL at the same time
DROP TABLE #temp;

旁注,全局临时表的行为方式不同,但我在这里专门只引用临时表,而不是全局表。


编辑:在内部范围内,我似乎错了。你实际上得到了一些非常奇怪的行为。采取以下措施:

CREATE TABLE #temp (ID int);
INSERT INTO #temp VALUES(1);
EXEC sys.sp_executesql N'CREATE TABLE #temp (ID int); SELECT * FROM #temp;';
SELECT *
FROM #temp
DROP TABLE #temp;

这将返回 2 个数据集,一个没有行,一个有 1 行。但是,如果您删除CREATEdeferred 语句中的 ,那么您会从两者中获得 1 行:

CREATE TABLE #temp (ID int);
INSERT INTO #temp VALUES(1);
EXEC sys.sp_executesql N'SELECT * FROM #temp;';
SELECT *
FROM #temp
DROP TABLE #temp;

这发生在 SQL Server 2019 上,但我确定我记得这种行为在以前的版本中不是这样的。也许我正在回忆(非常)旧的行为。


推荐阅读