避免oracle中全局临时表的方法
我们刚刚将 sql server 存储过程转换为 oracle 过程。 Sql Server SP 高度依赖于会话表 (INSERT INTO #table1...
),这些表在 Oracle 中被转换为全局临时表。我们最终为我们的 400 SP 提供了大约 500 GTT
现在我们发现,由于性能和其他问题,在 Oracle 中使用 GTT 被认为是最后的选择。
还有什么其他选择?收藏品?光标?
我们对 GTT 的典型用法如下:
插入 GTT
INSERT INTO some_gtt_1
(column_a,
column_b,
column_c)
(SELECT someA,
someB,
someC
FROM TABLE_A
WHERE condition_1 = 'YN756'
AND type_cd = 'P'
AND TO_NUMBER(TO_CHAR(m_date, 'MM')) = '12'
AND (lname LIKE (v_LnameUpper || '%') OR
lname LIKE (v_searchLnameLower || '%'))
AND (e_flag = 'Y' OR
it_flag = 'Y' OR
fit_flag = 'Y'));
更新 GTT
UPDATE some_gtt_1 a
SET column_a = (SELECT b.data_a FROM some_table_b b
WHERE a.column_b = b.data_b AND a.column_c = 'C')
WHERE column_a IS NULL OR column_a = ' ';
,然后从 GTT 中获取数据。这些只是示例查询,实际上查询非常复杂,包含大量联接和子查询。
我有一个由三部分组成的问题:
- 有人可以展示如何进行转型吗 上述示例查询 集合和/或游标?
- 自从 使用 GTT,您可以在本地工作 使用 SQL...为什么要远离 GTT?他们真的那么糟糕吗?
- 应该有什么指导方针 何时使用以及何时避免 GTT
We just converted our sql server stored procedures to oracle procedures. Sql Server SP's were highly dependent on session tables (INSERT INTO #table1...
) these tables got converted as global temporary tables in oracle. We ended up with aroun 500 GTT's for our 400 SP's
Now we are finding out that working with GTT's in oracle is considered a last option because of performance and other issues.
what other alternatives are there? Collections? Cursors?
Our typical use of GTT's is like so:
Insert into GTT
INSERT INTO some_gtt_1
(column_a,
column_b,
column_c)
(SELECT someA,
someB,
someC
FROM TABLE_A
WHERE condition_1 = 'YN756'
AND type_cd = 'P'
AND TO_NUMBER(TO_CHAR(m_date, 'MM')) = '12'
AND (lname LIKE (v_LnameUpper || '%') OR
lname LIKE (v_searchLnameLower || '%'))
AND (e_flag = 'Y' OR
it_flag = 'Y' OR
fit_flag = 'Y'));
Update the GTT
UPDATE some_gtt_1 a
SET column_a = (SELECT b.data_a FROM some_table_b b
WHERE a.column_b = b.data_b AND a.column_c = 'C')
WHERE column_a IS NULL OR column_a = ' ';
and later on get the data out of the GTT. These are just sample queries, in actuality the queries are really complext with lot of joins and subqueries.
I have a three part question:
- Can someone show how to transform
the above sample queries to
collections and/or cursors? - Since
with GTT's you can work natively
with SQL...why go away from the
GTTs? are they really that bad. - What should be the guidelines on
When to use and When to avoid GTT's
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我们先回答第二个问题:
几天前,我正在做一个概念验证,它将一个较大的 XML 文件 (~18MB) 加载到 XMLType 中。因为我不想永久存储 XMLType,所以我尝试将其加载到 PL /SQL 变量(会话内存)和临时表 将其加载到临时表中所需的时间是加载到 XMLType 变量中所需时间的五倍(5 秒与 1 秒相比)。它们被写入磁盘(特别是您指定的临时表空间),
如果您想缓存大量数据,那么将其存储在内存中会给 PGA 带来压力,如果您有大量会话,这并不好,所以这是一个权衡。内存和时间
:
您发布的查询可以合并到单个语句中:(
我只是简单地转换了您的逻辑,但是
case()
语句可以替换为更简洁的nvl2(trim (a.column_a), a.column_a, b.data_a)
)我知道你说你的查询更复杂,但你的第一个停靠点应该是考虑重写它们我知道打破它们是多么诱人。对许多用 PL/SQL 拼接在一起的婴儿 SQL 进行粗糙的查询,但纯 SQL 的效率要高得多,
要使用集合,最好在 SQL 中定义类型,因为它也使我们能够灵活地在 SQL 语句中使用它们。作为 PL/SQL,
这是一个示例函数,它返回一个结果集:
其实际情况是:
在该函数中,需要用列实例化类型,以避免出现 ORA-00947 异常。填充 PL/SQL 表类型时必需的:
最后,准则
当我们需要在同一会话中的不同程序单元之间共享缓存数据时,全局临时表非常好。例如,如果我们有一个由填充 GTT 单个函数生成的通用报告结构(尽管这也可以通过动态引用游标来实现...)
如果我们有大量中间处理,而这些中间处理太复杂而无法通过单个 SQL 查询来解决,那么全局临时表也很好 。特别是如果该处理必须应用于检索到的行的子集,
但一般来说,我们不需要使用临时表,所以
Let's answer the second question first:
A couple of days ago I was knocking up a proof of concept which loaded a largish XML file (~18MB) into an XMLType. Because I didn't want to store the XMLType permanently I tried loading it into a PL/SQL variable (session memory) and a temporary table. Loading it into a temporary table took five times as long as loading it into an XMLType variable (5 seconds compared to 1 second). The difference is because temporary tables are not memory structures: they are written to disk (specifically your nominated temporary tablespace).
If you want to cache a lot of data then storing it in memory will stress the PGA, which is not good if you have lots of sessions. So it's a trade-off between RAM and time.
To the first question:
The queries you post can be merged into a single statement:
(I have simply transposed your logic but that
case()
statement could be replaced with a neaternvl2(trim(a.column_a), a.column_a, b.data_a)
).I know you say your queries are more complicated but your first port of call should be to consider rewriting them. I know how seductive it is to break a gnarly query into lots of baby SQLs stitched together with PL/SQL but pure SQL is way more efficient.
To use a collection it is best to define the types in SQL, because it gives us the flexibility to use them in SQL statements as well as PL/SQL.
Here's a sample function, which returns a result set:
And here it is in action:
In the function it is necessary to instantiate the type with the columns, in order to avoid the ORA-00947 exception. This is not necessary when populating a PL/SQL table type:
Finally, guidelines
Global temp tables are very good when we need share cached data between different program units in the same session. For instance if we have a generic report structure generated by a single function feeding off a GTT which is populated by one of several procedures. (Although even that could also be implemented with dynamic ref cursors ...)
Global temporary tables are also good if we have a lot of intermediate processing which is just too complicated to be solved with a single SQL query. Especially if that processing must be applied to subsets of the retrieved rows.
But in general the presumption should be that we don't need to use a temporary table. So
通常,我会使用 PL/SQL 集合来存储少量数据(可能是一千行)。如果数据量更大,我会使用 GTT,这样它们就不会导致进程内存过载。
因此,我可能会从数据库中选择几百行到 PL/SQL 集合中,然后循环遍历它们以进行一些计算/删除一些或其他操作,然后将该集合插入到另一个表中。
如果我要处理数十万行,我会尝试将尽可能多的“繁重”处理推入大型 SQL 语句中。这可能需要也可能不需要 GTT。
您可以使用 SQL 级集合对象作为在 SQL 和 PL/SQL 之间轻松转换的对象
Generally I'd use a PL/SQL collection for storing small volumes of data (maybe a thousand rows). If the data volumes were much larger, I'd use a GTT so that they don't overload the process memory.
So I might select a few hundred rows from the database into a PL/SQL collection, then loop through them to do some calculation/delete a few or whatever, then insert that collection into another table.
If I was dealing with hundreds of thousands of rows, I would try to push as much of the 'heavy lifting' processing into large SQL statements. That may or may not require GTT.
You can use SQL level collection objects as something that translates quite easily between SQL and PL/SQL