【问题标题】:Local Temporary table in Oracle 10 (for the scope of Stored Procedure)Oracle 10 中的本地临时表(适用于存储过程的范围)
【发布时间】:2010-11-14 14:29:19
【问题描述】:

我是甲骨文的新手。我需要在存储过程中处理大量数据。我正在考虑使用临时表。我正在使用连接池,并且应用程序是多线程的。

有没有一种方法可以创建临时表,即每次调用存储过程时都会创建不同的表实例,从而不会混淆来自多个存储过程调用的数据?

【问题讨论】:

    标签: sql database oracle stored-procedures temp-tables


    【解决方案1】:

    您说您是 Oracle 的新手。我猜你已经习惯了 SQL Server,在这里使用临时表是很常见的。 Oracle 的工作方式不同,因此它不太常见,因为它不太必要。

    请记住,使用临时表会带来以下开销:

    1. 读取数据以填充临时表
    2. 将临时表数据写入文件
    3. 在您的进程启动时从临时表中读取数据
    大部分活动对于帮助您完成工作毫无用处。一个更好的主意是看看你是否可以在一个动作中完成所有事情,最好是纯 SQL。

    顺便说一句,您提到的连接池引发了另一个问题。处理大量数据的进程不适合在 OLTP 模式下运行。你真的应该考虑启动一个后台(即异步)进程,可能是一个数据库作业,来运行你的存储过程。如果您想定期运行此作业,则尤其如此,因为我们可以使用 DBMS_SCHEDULER 来自动管理此类事情。

    【讨论】:

      【解决方案2】:

      我最近使用了全局临时表,它的行为非常不受欢迎。

      我在过程调用中使用临时表来格式化一些复杂的数据,一旦数据被格式化,就将数据传递给前端(Asp.Net)。 在第一次调用该过程时,我曾经获取正确的数据,并且任何后续调用都用于向我提供除当前调用之外的最后一次过程调用的数据。

      我在网上进行了调查,发现了一个在提交时删除行的选项。 我认为这会解决问题..猜猜怎么着?当我使用提交删除行选项时,我总是从数据库中获取 0 行。所以我不得不回到提交时保留行的原始方法,即使在提交事务之后也会保留行。此选项仅在会话终止后才从临时表中清除行。 然后我发现了这篇文章并了解了跟踪会话的 call_id 的列。

      我实施了该解决方案,但它仍然可以解决问题。 然后我在开始任何处理之前在我的程序中写了以下语句。

      从临时表中删除;

      上面的 statemnet 成功了。我的前端正在使用连接池,并且在每次过程调用之后它都在提交事务,但仍将连接保留在连接池中,并且后续请求使用相同的连接,因此每次调用后数据库会话都没有终止.. 在进行任何处理之前从临时表中删除行使其工作....

      在我找到这个解决方案之前,它让我发疯......

      【讨论】:

        【解决方案3】:

        在 Oracle 中,几乎不需要在运行时创建对象。

        全局临时表很可能是解决您问题的最佳方案,但是由于您没有确切说明为什么需要临时表,我建议您先检查是否需要临时表;您可能认为需要多个查询的事情可以用一个 SQL 完成。

        也就是说,我过去在需要为同一会话中的多个上下文在表中维护单独的“空间”的应用程序中非常成功地使用了全局临时表;这是通过添加一个初始设置为 1 的附加 ID 列(例如“CALL_ID”)来完成的,随后对该过程的调用将增加该 ID。必须在某处使用全局变量来记住 ID,例如在包体中声明的包全局变量。例如:

        PACKAGE BODY gtt_ex IS
           last_call_id integer;
           PROCEDURE myproc IS
              l_call_id integer;
           BEGIN
              last_call_id := NVL(last_call_id, 0) + 1;
              l_call_id      := last_call_id;
              INSERT INTO my_gtt VALUES (l_call_id, ...);
              ...
              SELECT ... FROM my_gtt WHERE call_id = l_call_id;
           END;
        END;
        

        您会发现 GTT 即使在高并发的情况下也表现得非常好,当然比使用普通表要好。最佳做法是设计您的应用程序,使其永远不需要从临时表中删除行 - 因为 GTT 会在会话结束时自动清除。

        【讨论】:

          【解决方案4】:

          如果您使用的是事务(而不是会话)级别的临时表,那么这可能已经完成了您想要的操作...只要每个调用只包含一个事务? (您没有提供足够的细节来说明是否是这种情况)

          所以,要明确一点,只要每个调用只包含一个事务,那么您使用连接池就没有关系,因为在每次 COMMIT 或 ROLLBACK 之后数据将从临时表中清除无论如何。

          (另一种选择是在每次调用中使用 EXECUTE IMMEDIATE 创建一个唯一命名的临时表。但不确定性能如何。)

          【讨论】:

          • +1:您不需要为每个会话重新创建临时表。创建一个临时表 ONCE,每个会话只会看到自己的数据。
          猜你喜欢
          • 2016-09-29
          • 2021-02-11
          • 1970-01-01
          • 2011-10-29
          • 1970-01-01
          • 2015-02-15
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多