是否正在考虑不良形式的程序共享临时表?

时间:2009-07-14 19:42:31

标签: sql sql-server

我有2个程序。一个构建临时表,另一个(或其他几个)使用在第一个proc中创建的临时表。这被认为是不好的形式吗?我在这里走进现有的代码库,它使用了这种模式。这当然困扰我,但我不能说这显然是一个坏主意。我发现这是一种令人讨厌的模式 - 有些东西闻起来很烂但我不知道是什么。我更喜欢在本地构建表,然后用exec填充它。但是这需要只返回一个表的proc,这在现有的代码库中是不常见的。

SQL的大师是否回避这种临时表共享?如果是这样,为什么?我正在努力形成一个考虑周全的意见,并希望得到一些意见。

观点是否可行?

性能怎么样?在本地构建@table或在“填充”过程中构建#table会更好吗?

这里对所有方法进行了很好的讨论:http://www.sommarskog.se/share_data.html

8 个答案:

答案 0 :(得分:4)

作为编程范例,它很丑陋,因为它涉及传递带外参数('上下文参数'),这些参数未在过程签名中明确调出。这会产生隐藏的依赖关系并导致意大利面效应。

但是在SQL的特定上下文中,只有无选择。 SQL与数据集一起使用,您不能将这些数据集作为过程参数来回传递。你有几个选择:

  • 通过客户端。太明显不是一个真正的选择。
  • 带有分隔符类型的XML或字符串,用于表示结果。在任何方面都不是一个严肃的选择,它们可能会提供良好的“编程”语义(即Demeter Law一致性)但是当性能发挥作用时它们真的很糟糕。
  • 像Raj建议的共享表(在tempdb或appdb中)。您正在失去#temp自动维护(ref count上的清理变为0),您必须为创建竞争条件做好准备。它们也可以无缘无故地变大(它们不再被会话分割成单独的行集,如#temp表一样)。
  • @tables。它们的范围是声明上下文(即程序),不能在程序之间来回传递。我还发现了some nasty problems under memory pressure

答案 1 :(得分:1)

共享临时表的最大问题在于它将外部依赖项引入到乍一看可能不明显的过程中。假设您有一些调用过程p2的过程p1和一个临时表#t1用于在两个过程之间传递信息。如果你想隔离运行p2以查看它的作用,你必须创建一个“harness”来定义#t1然后才能运行它。在T-SQL中使用临时表通常相当于在其他语言中使用全局变量 - 不推荐但有时不可避免。

SQL Server 2008现在具有表值参数,但Microsoft选择在此版本中将它们设置为只读。但是,这意味着您不必在之前的某些场景中使用临时表。

我的建议是,如果必须使用它们,但要彻底记录它们的使用。如果你有一些依赖于临时表运行的proc,请在注释中调用它。

答案 2 :(得分:1)

有时这是唯一的出路。如果您需要这样做,那么文档,文档,文档事实。这是一种明确的方法,将表定义作为注释放在参数部分......

CREATE PROCEDURE xyz
(
     @param1  int            --REQUIRED, what it does
    ,@param2  char(1)        --OPTIONAL, what it does
    ,@param3  varchar(25)    --OPTIONAL, what it does
    --this temp table is required and must be created in the calling procedure
    --#TempXyz (RowID      int          not null primary key
    --         ,DataValue  varchar(10)  not null
    --         ,DateValue  datetime     null
    --         )
)

还在创建临时表的调用过程中记录....

--** THIS TEMP TABLE IS PASSED BETWEEN STORED PROCEDURES **
--** ALL CHANGES MUST TAKE THIS INTO CONSIDERATION!!!    **
CREATE TABLE #TempXyz 
(RowID      int          not null primary key
,DataValue  varchar(10)  not null
,DateValue  datetime     null
)

答案 3 :(得分:0)

我遇到了同样的问题。从个人经历我可以说:

如果有办法避免在多个过程中使用#temp表,请使用它。 #temp表很容易丢失,如果你不小心的话,很容易增长tempdb。

在某些情况下,这种方法是不可避免的(我的经典示例是某些报告功能,它根据报告配置以不同方式构建数据)。如果仔细管理,我相信在这些情况下这是可以接受的。

答案 4 :(得分:0)

分享临时表并不是一个坏主意。但是我们需要确保两个proc同时不应该操纵表级数据,导致Dirty Read / Write场景。这也有助于使用单个表[集中]和处理它的过程来获得同步数据。 关于性能,确实如果多个proc共享相同的临时数据,将会降低性能。但与此同时,单个表[每个Proc]会导致内存消耗增加,

答案 5 :(得分:0)

我在少数情况下使用过这种方法。但我总是将临时表声明为完全限定的表,而不是使用#tablename。

CREATE TABLE [tempdb].[dbo].[tablename]

通过这种方法,可以很容易地跟踪临时表。

拉​​吉

答案 6 :(得分:0)

我看到避免使用临时表的另一种技术是所谓的“SPID-keyed”表。您可以使用以下属性定义常规表,而不是临时表:

CREATE TABLE spid_table
(
   id INT IDENTITY(1, 1) NOT NULL,
   -- Your columns here
   spid INT NOT NULL DEFAULT @@SPID,
   PRIMARY KEY (id)
);

在您的程序中,您将获得如下代码:

SELECT @var = some_value
FROM spid_table
WHERE -- some condition
AND spid = @@SPID;

并在处理结束时:

DELETE FROM spid_table
WHERE spid = @@SPID;

这样做的最大缺点是该表使用与数据库其余部分相同的恢复模型,因此记录了所有这些瞬态插入,更新和删除。唯一真正的优点是依赖性比使用临时表更明显。

答案 7 :(得分:0)

我想,如果第二个过程检查是否存在临时表,那就没关系。前进,如果是这样的话。此外,如果临时表不存在,它可能会引发错误,要求用户先运行proc1。

为什么工作分为2个存储过程?不能在1个过程中完成任务吗?