当存储过程可以由不同用户同时运行时,是否建议使用临时表?

use*_*947 8 sql-server stored-procedures t-sql

我正在研究一个从活动目录中检索 objectGUID 的存储过程。我将结果存储在临时表中,然后在输出参数中返回值以供其他进程使用。SP 将从不同的存储过程以及 Web 应用程序 PHP、ASP Classic 和 ASP.Net 中调用。

我在这里读到(关于临时表):

如果在存储过程中创建,它们将在存储过程完成后销毁。此外,任何特定临时表的范围是创建它的会话;这意味着它只对当前用户可见。多个用户可以创建一个名为 #TableX 的临时表,同时运行的任何查询都不会相互影响——他们将保持自治事务,表将保持自治对象。您可能会注意到我的示例临时表名称以“#”符号开头。

听起来我很高兴,但我想得到一些建议,以确保没有任何我不知道的问题。这里是SP。

提前致谢。

CREATE PROCEDURE stp_adlookup
@user varchar(100),
@objectGUID varbinary(256) OUTPUT
AS
SET NOCOUNT ON;
DECLARE @qry char(1000)
CREATE TABLE #tmp(
objectGUID nvarchar(256)
)

SET @qry = 'SELECT *
FROM openquery(ADSI, ''
SELECT  objectGUID              
FROM    ''''LDAP://mydomaincontroller.com''''
WHERE sAMAccountName = ''''' + @user + '''''
'')'
INSERT INTO #tmp
EXEC(@qry)
SELECT @objectGUID=CAST(objectGUID as varbinary(256))  FROM #tmp;
DROP TABLE #tmp
SET NOCOUNT OFF;
GO
Run Code Online (Sandbox Code Playgroud)

Aar*_*and 15

是的,每个用户都将获得自己的#temp 表副本,即使他们同时运行。

(但是,不要使用全局 ##temp 表,用两个前导磅/哈希符号表示。)

但是为什么这里需要一个#temp 表呢?这样的事情应该可以工作(未经测试,因为我附近没有 LDAP):

CREATE PROCEDURE dbo.stp_adlookup -- ALWAYS use schema prefix
  @user varchar(100),
  @objectGUID varbinary(256) OUTPUT
AS
BEGIN -- use body wrappers
  SET NOCOUNT ON;

  DECLARE @qry nvarchar(max); -- don't use CHAR for dynamic SQL

  SET @qry = N'SELECT @o = objectGUID
    FROM openquery(ADSI, ''SELECT  objectGUID              
      FROM    ''''LDAP://mydomaincontroller.com''''
      WHERE sAMAccountName = ''''' + @user + ''''''')';

  -- can probably parameterize the above, but those single
  -- quotes are a nightmare. Not sure if they're necessary
  -- but I do not feel like trying to untangle them.

  EXEC sys.sp_executesql @qry, N'@o UNIQUEIDENTIFIER', @o = @objectGUID OUTPUT;

  -- SET NOCOUNT OFF; -- don't do this.
END
GO
Run Code Online (Sandbox Code Playgroud)


Kri*_*yer 8

您应该没问题,我们这里有无数的 SP,它们每天使用名称相同的临时表运行 1000 次,并且没有任何问题。

这是一个直观的例子。我在我的 SQL2014 实例上创建了 2 个表。一个是从 SPID 53 创建的,另一个是从 SPID 57 创建的。 下面是它在对象资源管理器中的样子:

在此处输入图片说明

正如您所看到的,尽管它们的“命名”相同,但在最后,有一组可爱的字符使表格与众不同。唯一的区别是我从不同的查询窗口执行了 CREATE 语句。这只是展示它的一种视觉方式。当您查询#tmp 表时,您只查询适用于您的会话的表。

不过,我会提出一个建议。这是我完全内疚的事情,我正在努力过渡到。使用sp_executesql代替EXEC()。亚伦·伯特兰 (Aaron Bertrand) 将其写为“踢球的坏习惯”之一:

基本上,使用 sp_executesql 将减少 SQL 注入的机会,并且执行计划可以被重用的机会更高。Aaron 在文章中更详细地介绍了,但那是 1000 英尺的视图。

  • 我只想补充一点,为每个过程唯一地命名本地临时表会很有用,因为该过程可能会从另一个已经创建了具有相同名称的本地临时表的过程中调用。 (5认同)