【问题标题】:Global Temp Tables - SQL Server vs Oracle全局临时表 - SQL Server 与 Oracle
【发布时间】:2012-02-13 08:00:50
【问题描述】:

我正在使用 Oracle 11g 全局临时表,因为我需要一个解决方案,在该解决方案中我可以将行添加到临时表以进行连接,并且我只希望将添加到临时表的行包含在 Oracle 连接/会话中。我在 Oracle 中使用全局临时表,因为我希望该表存在于会话之间,因此不必在每次创建查询时都重新创建它。这很好。

我的Oracle表定义如下:

CREATE GLOBAL TEMPORARY TABLE book_id_temp 
( 
   book_id RAW(32)
)ON COMMIT DELETE ROWS;

我在 SQL Server 2008-R2 端也有相同的数据库结构,并且在 SQL Server 中需要类似的解决方案。我想:

  1. 打开 SQL 连接 (ADO.NET)
  2. 在交易中:
  3. -向临时表添加行。
  4. -将它们加入另一个表,选择结果
  5. - 仅将在此会话期间添加的行包含在联接中。另一个线程可能正在同一个临时表上执行。那么本地临时表可能在这里最好吗?
  6. 回滚整个事务。

根据我对 SQL Server 中全局临时表的了解,这些表在连接结束后存在,就像常规表一样,也像 Oracle 中的全局临时表。但是,目前尚不清楚数据的范围。是否只有创建行的 SQL Server 会话才能访问它,就像在 Oracle 中一样? SQL Server 全局临时表对数据的可访问性如何?您对实现我的目标的替代方案有什么建议吗?

【问题讨论】:

  • Oracle 全局临时表也需要被截断,具体取决于操作...如果可以选择,我会在 SQL Server 中的临时表上使用表变量,但您需要说明您的需要当连接丢失时的持久性以获得真正的帮助。为什么不直接制作一张实际的表格?
  • 我希望表在会话之间存在,这样就不必在每次创建查询时都重新创建它。
  • 听起来就像你想要一个本地临时表,而不是一个全局临时表。你能描述一下你需要什么语义吗?
  • @Damien_The_Unbeliever,我已经添加了我更确切需要的细节。希望这能回答您的问题。

标签: sql-server oracle temp-tables


【解决方案1】:

Oracle 中的临时表是保存会话本地临时数据的永久对象。 SQL Server 中的临时表是临时对象。

  1. 在 SQL Server 中,全局临时表保存对所有会话可见的数据。 “全局临时表在创建后对任何用户和任何连接都是可见的。” http://msdn.microsoft.com/en-us/library/ms186986.aspx
  2. 全局临时表仍然是临时对象,不会无限期地持续存在,可能需要在使用前创建。 “当所有引用该表的用户与 SQL Server 实例断开连接时,全局临时表将被删除。” http://msdn.microsoft.com/en-us/library/ms186986.aspx

我发现本地临时表或表变量与Oracle的全局临时表最接近,最大的区别是您必须每次都创建它。

通常,在像您这样的情况下,第 3 步,将行添加到临时表,将通过执行 select ... into #temp_table_name ....(相当于 Oracle create table ... as select ...http://msdn.microsoft.com/en-us/library/ms188029.aspx 来完成

此外,您不能在存储过程中执行以下操作:(伪代码。)

begin proc
   call another proc to create local temp table.
   use temp table
end proc

本地临时表在从创建它们的存储过程返回时被销毁。

2014-10-14 更新:本地临时表的行为在 SQL Server 的并行数据仓库 v 版本中有所不同。临时表在退出创建它们的存储过程时不会被删除,而是在会话的其余部分继续存在。观察到此行为:

select @@version
Microsoft SQL Server 2012 - 10.0.5108.1 (X64) Jun 24 2014 20:17:02 Copyright (c) Microsoft Corporation Parallel Data Warehouse (64-bit) on Windows NT 6.2 <X64> (Build 9200: )

【讨论】:

    【解决方案2】:

    默认情况下,SQL Server 上的临时表是本地的。会话结束后,该表将被删除。如果您执行如下脚本:

    create table #Foo (
           FooID  int
          ,FooCode1  varchar (20)
    )
    
    insert table #Foo (FooID, FooCode1)
    values (1001, 'X')
    
    insert table #Foo (FooID, FooCode1)
    values (1002, 'Y')
    
    select f.FooID
          ,f.FooCode1
          ,b.BarID
          ,b.BarCode1
      from #foo f
      join bar b
        on bar.FooID = f.FooID -- (or whatever predicate)
    

    查询将仅返回与您在此会话中插入 #Foo 的内容相连接的行。 #Foo 是会话本地的;您可以使用自己的#Foo 临时表进行多个会话,而不必担心命名空间冲突。当会话关闭时,临时表将被丢弃。如果您使用的是持久数据库连接(例如客户端-服务器桌面应用程序),您还可以在完成后显式删除 #Foo。

    【讨论】:

    • 我创建一个 IDbConnection 并管理事务(非持久性)并关闭连接。当连接关闭时,会话也会关闭,对吗?
    • 是的,如果您关闭连接,会话将关闭。
    【解决方案3】:

    如果您在 tempdb 数据库中手动创建表,您将获得或多或少相同的效果:

    USE tempdb;
    
    CREATE TABLE foo...
    

    然后解决他们:

    select * from tempdb..foo
    

    这些表不会在会话之间被删除。您需要手动截断它们,不等同于 ON COMMIT DELETE ROWS。

    【讨论】:

    • 我当前的 ADO.NET 实现是,在将记录插入临时表并执行 Join 之后,我在 IDbConnection 上执行 Rollback(),这样实际上可能就足够了。你说表不会被删除,但是它的内容呢?我在想,如果我从来没有真正提交过事务,那么没有其他活动连接甚至可以访问数据
    • 它会起作用,但效率极低。 SQL Server 中的回滚非常容易锁定并且速度很慢,尤其是对于大数据。使用会话级临时表效率更高,或者如果您坚持使用全局表,则在完成后截断它。
    【解决方案4】:

    如果您在 SQL Server 中创建全局临时表 (##table),它将“活动”并可以通过其他会话访问,直到该会话关闭。此外,在原始会话关闭之前,您将无法以相同的名称为不同的会话创建该全局临时表,您会发现该表已经存在。出于您的目的,全局临时表不是一个好的解决方案。

    本地临时表 (#table) 会更好,并且可以实现您想要做的事情。

    希望对你有帮助

    【讨论】:

    • 全局临时表的记录是否只能在创建它们的事务中访问?我不希望每次查询都创建表。
    • 否,SQL Server 全局临时表 (##table_name) 中的记录对所有会话可见。
    猜你喜欢
    • 2014-09-01
    • 2017-10-02
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 2016-04-02
    • 1970-01-01
    • 2010-09-29
    相关资源
    最近更新 更多