在 Oracle 中使用临时 table 优化 SQL

Optimizing SQL by using temporary table in Oracle

我有一个数据清理程序,可以从两个 table 的卡片行中删除相同的数据。 这两个更新语句都使用相同的子查询来检测应该更新哪些行。

 UPDATE table_1 SET card = NULL WHERE id in
               (select id from sub_table WHERE /* complex clause here */);

 UPDATE table_2 SET card = NULL WHERE id in
               (select id from sub_table WHERE /* complex clause here */);

使用 Oracle Temporary table 是优化我的代码的好解决方案吗?

CREATE TEMPORARY TABLE tmp_sub_table AS
select id from sub_table WHERE /* complex clause here */;

UPDATE table_1 SET card = NULL WHERE id in (select * from tmp_sub_table);    
UPDATE table_2 SET card = NULL WHERE id in (select * from tmp_sub_table);

我应该使用本地临时table还是全局临时table?

全局临时 Table 是持久数据结构。当我们 INSERT 时,数据被写入磁盘,当我们 SELECT 时,数据被从磁盘读取。所以这是相当多的磁盘 I/O:从 运行 两次相同的查询中节省的成本必须大于所有这些写入和读取的成本。

需要注意的一件事是 GTT 是建立在临时 Table 空间上的,因此您可能会与其他正在进行排序的长 运行 进程发生争用,等等。这是一个很好的有一个单独的临时 Table 空间的想法,仅供 GTT 使用,但没有多少 DBA 这样做。

另一种解决方案是使用集合将记录的子集存储在内存中并使用批量处理。

 declare
     l_ids sys.ocinumberlist;
     cursor l_cur is
         select id from sub_table WHERE /* complex clause here */
         order by id
         ;
begin
    open lcur;
    loop
        fetch lcur bulk collect into l_ids limit 5000;
        exit when l_ids.count() = 0;

        update table1 
        set card=null
        where id member of l_ids;

        update table2 
        set card=null
        where id member of l_ids;

    end loop;
end;

"updating many rows with one update statement ... works much faster than updating separately using Looping over cursor"

这是正常的建议。但这是批量操作:一次更新五千行,因此比逐行更新快。批处理的大小由 BULK COLLECT ... LIMIT 子句控制:您不想将值设置得太高,因为集合在 session memory 中,但因为您只是select 一栏 - 和一个数字 - 也许你可以提高它。

一如既往地调整是 基准测试 的问题。您确定 运行 两次子查询是高成本操作吗?

select id from sub_table WHERE /* complex clause here */

如果它看起来太慢,您需要测试其他方法并查看它们是否更快。也许全局临时 Table 比批量操作更快。通常内存访问比磁盘访问快,但您需要查看哪种最适合您。