可以使用全局临时表吗?

时间:2017-07-10 16:59:58

标签: sql sql-server

我有一个概念可以这样描述的查询:

CREATE TABLE ##MyTable (
 -- rows  
)
INSERT INTO ##MyTable (...)
/*inserted SELECT */

WHILE ....
BEGIN
-- do some actions using data from temp table 
END 

EXEC msdb.dbo.sp_send_dbmail
    -- other data needed for email sending ...
    @query = N'select ... FROM ##MyTable;',

-- drop the temporary table
DROP TABLE ##MyTable 

所以,我选择一些数据到全局临时表,他们使用它,他们发送电子邮件,最后删除这个临时表。

此查询用作任务,该任务会定期启动以自动执行数据库中的某些进程。

我怀疑的那一刻 - 是全球临时表。如果我打算只在这个自动化脚本中使用这个表(带有这样的名字),我能确定不会发生冲突或其他类似的错误吗?它看起来不应该,因为没有用户或程序连接将使用此表,因此逻辑很简单:我的任务每周启动一次,创建此表然后删除它。但它真的如此,或者我想念一些时刻,在这里使用全球临时表不是一个好主意吗?

PS:我试过使用当地的临时工。表,但是sp_send_dbmail返回错误(据我所知,当sp_send_dbmail启动时,表已被删除):

Msg 22050, Level 16, State 1, Line 0
Error formatting query, probably invalid parameters
Msg 14661, Level 16, State 1, Procedure sp_send_dbmail, Line 504
Query execution failed: Msg 208, Level 16, State 1, Server SERVER\SERVER, Line 1
Invalid object name '#MyTable'.

3 个答案:

答案 0 :(得分:4)

您认为会话临时表不能与sp_send_dbmail一起使用是正确的。引用文档,强调我的:

  

[@ query =]'query'是要执行的查询。查询结果   可以作为文件附加,也可以包含在电子邮件正文中   信息。查询的类型为nvarchar(max),可以包含任何有效的查询   Transact-SQL语句。 请注意,查询是在a中执行的   单独的会话,所以脚本调用中的局部变量   查询无法使用sp_send_dbmail

任何用户都可以创建全局临时表,因此可能会发生冲突。如果任务的执行时间过长并且与下一次运行重叠,则会发生这种情况。我可以考虑三种方法来解决这个问题。

  1. 使用NEWID()函数创建临时表的名称。这将确保脚本的两次执行创建具有不同名称的表。
  2. 使用其中包含列的永久表,该列由每次执行脚本唯一设置,以便传递给sp_send_dbmail的查询可以引用它。
  3. 我可能会考虑使用sp_getapplock创建一个锁,其他脚本可以检查该表是否正在使用。 (注意,如果脚本执行经常重叠,这可能会导致积压产生)。

答案 1 :(得分:1)

全局临时表意味着任何其他用户也可以尝试创建相同的全局临时表。这会导致碰撞。

在大多数情况下,创建和使用永久表对我们很有帮助。使用永久表可以获得很多优势。你可以掌握事情的历史。如果您认为数据会增长,您可以设置管家,以删除超过几天或几周的数据。

在我们的项目中,我们的指导是:创建一个“真正的”临时表或“真正的”永久表。

答案 2 :(得分:1)

  1. 不使用全局临时表。将您的查询输出转换为HTML正文,这里可以帮助您https://dba.stackexchange.com/questions/83776/need-to-send-a-formatted-html-email-via-database-mail-in-sql-server-2008-r2

  2. 使用全局临时表但考虑减少冲突的可能性

    一个。试试@Martin Brown的建议。

    湾如果你的while循环需要一些时间才能完成,你可以先为它创建一个本地临时表。仅在数据库邮件之前将输出转储到全局临时表。邮件发送后立即删除。