我是oracle的新手。我需要在存储过程中处理大量数据。我正在考虑使用临时表。我正在使用连接池,应用程序是多线程的。
有没有办法以每次调用存储过程创建不同表实例的方式创建临时表,以便来自多个存储过程调用的数据不会混淆?
答案 0 :(得分:8)
你说你是Oracle新手。我猜你已经习惯了SQL Server,在那里使用临时表很常见。 Oracle的工作方式不同,因此不太常见,因为它不太必要。
请记住,使用临时表会产生以下开销:
顺便提一下,您提到的连接池会引发另一个问题。重置大量数据的进程不适合在OLTP模式下运行。你真的应该考虑启动一个后台(即asysnchronous)进程,可能是一个数据库作业,来运行你的存储过程。如果你想定期运行这个工作,尤其如此,因为我们可以使用DBMS_SCHEDULER来自动管理这些工作。
答案 1 :(得分:3)
如果你正在使用事务(而不是会话)级临时表,那么这可能已经做了你想要的......只要每个调用只包含一个事务? (你没有提供足够的细节来明确是否是这种情况)
因此,要清楚,只要每个调用只包含一个事务,那么您使用连接池就没关系,因为在每次COMMIT或ROLLBACK之后数据将被清除出临时表反正。
(另一种选择是使用EXECUTE IMMEDIATE在每次调用中创建一个唯一命名的临时表。不知道这会有多高效。)
答案 2 :(得分:2)
在Oracle中,几乎不需要在运行时创建对象。
全局临时表很可能是您问题的最佳解决方案,但是由于您还没有确切说明为什么需要临时表,我建议您首先检查是否需要临时表;使用一个SQL的时间有一半你可能认为需要多次查询。
也就是说,我过去使用全局临时表非常成功地在需要在同一会话中为多个上下文维护表中的单独“空间”的应用程序中;这是通过添加最初设置为1的附加ID列(例如“CALL_ID”)来完成的,并且对该过程的后续调用将增加该ID。必须在某处使用全局变量记住ID,例如包体中声明的包全局变量。 E.G:
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会在会话结束时自动清除。
答案 3 :(得分:1)
我最近使用了全局临时表,但表现得非常糟糕。
我正在使用临时表来格式化过程调用中的一些复杂数据,并且在格式化数据后,将数据传递到前端( Asp.Net )。 在第一次调用该过程时,除了当前调用之外,我曾经获得了正确的数据以及用于从上次过程调用中获取数据的任何后续调用。
我在网上调查并发现了一个删除提交行的选项。 我以为这会解决问题..猜怎么着?当我在提交删除行选项上使用时,我总是习惯从数据库中获取0行。所以我不得不回到提交保留行的原始方法,即使在提交事务之后也会保留行。此选项仅在会话终止后清除临时表中的行。 然后我发现了这篇文章,并了解了跟踪会话call_id的专栏。
我实施了该解决方案,但仍然可以解决问题。 然后我在开始任何处理之前在我的程序中写了以下声明。
从Temp_table删除;
上面的statemnet成功了。我的前端正在使用连接池,并且在每个过程调用之后它都是委托事务但仍然保持连接池中的连接并且后续请求使用相同的连接,因此数据库会话在每次调用后都没有终止。 在判断任何处理之前从临时表中删除行使其工作....
在我找到这个解决方案之前,它让我疯了......