1

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

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

4

4 回答 4

8

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

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

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


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

于 2009-07-28T11:18:06.787 回答
3

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

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

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

于 2009-07-28T07:04:01.930 回答
2

在 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 会在会话结束时自动清除。

于 2009-07-28T10:47:43.507 回答
1

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

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

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

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

从 Temp_table 中删除;

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

它让我发疯,直到我找到了这个解决方案......

于 2009-12-04T16:25:31.463 回答