Oracle 使用临时表或其他方法

Posted

技术标签:

【中文标题】Oracle 使用临时表或其他方法【英文标题】:Oracle use temporary table or some other method 【发布时间】:2019-05-13 21:29:24 【问题描述】:

在 Oracle 中,需要在存储过程中多次重用查询结果。想知道临时表是否是推荐的方式或其他方式......

首先我根据某些输入参数创建一个结果集。

然后进行一些检查以查看表 1 中是否出现任何结果集行。简单的连接和计数就足够了。 如果 count > 0 则返回。 如果 count == 0 则我将结果集中的选定值(基于某些条件)插入表 1。

是否应该使用临时表或其他东西以获得最佳性能?

谢谢,

【问题讨论】:

感谢 N. Kaufman。更多信息会有所帮助——插入表 1 后,您是否会继续进一步重新使用查询结果?从描述来看,它看起来只是一种用途。如果您只是有条件地插入到一个表中,则可能根本不需要 PLSQL(至少对于 insert-if-not-present 不需要);有条件的INSERTMERGE 可能就足够了。另外,您要处理多少数据?这是数百/数千,还是数百万(您是否尝试过仅将其保存在内存中?) 当然,感谢您的回复。我首先使用结果集(这是一个复杂且有点昂贵的查询,因此想要存储结果)来比较表 1 中是否存在数据。这是使用 #1。如果不存在,则我插入表 1,选择行从这个结果集中。这不是用途#2吗?再次感谢。 在此之后,我将在我的过程中进行更多插入等操作(但不使用此结果集)。数据不会超过 20 行,但获取它们的查询既复杂又昂贵。如果我已经正确解释了这个问题,请告诉我。再次感谢。 感谢 N. Kaufman。我刚才提到的概念是,可以在一个 sql 语句中检查匹配并将条件应用于插入。测试和基准测试始终是最好的判断方式,但乍一看,我认为临时表不是必需的(尽管它也可以工作,很好的基准测试)。可以将这些保存在过程中的内存中,或者只是进行条件插入。我将添加这些方法的一些示例,但可能还有其他方法。 我查看了我的场景,发现我将根据某些条件将数据从结果集中插入到 2 个表中。因此,如果我的结果集中有 20 行,在确认 Table1 中不存在任何内容后,我将在 Table1 中插入一些,在 Table2 中插入其余的 【参考方案1】:

鉴于上次更新,您似乎需要在多个表中进行质量不同的插入,并在多个(不同)测试中使用昂贵查询的结果。

最好进行测试和基准测试(比较优缺点,以及临时表与其他方法的性能)。我将在此处包含另一种样式,它只是将结果拉入内存,可以根据需要在内存中查询它们(或迭代、计数等)

下面是一个例子:

-- 示例数据:

CREATE TABLE TABLE_1 (LOREM_IPSUM NUMBER);
INSERT INTO TABLE_1 VALUES (6);
COMMIT;

-- 保存数据的自定义类型

CREATE OR REPLACE TYPE EXPENSIVE_QUERY_TYPE IS OBJECT(LOREM_IPSUM NUMBER);
/
CREATE OR REPLACE TYPE EXPENSIVE_QUERY_RESULT IS TABLE OF EXPENSIVE_QUERY_TYPE;
/

-- 示例块:

DECLARE
    V_EXPENSIVE_RESULT EXPENSIVE_QUERY_RESULT := EXPENSIVE_QUERY_RESULT();
    V_TABLE_1_TEST INTEGER;
BEGIN
    SELECT EXPENSIVE_QUERY_TYPE(LEVEL)
    BULK COLLECT INTO V_EXPENSIVE_RESULT
    FROM DUAL
    CONNECT BY LEVEL <= 5;

    SELECT COUNT(*) INTO V_TABLE_1_TEST
        FROM TABLE_1
            WHERE EXISTS(SELECT 1 FROM TABLE(V_EXPENSIVE_RESULT) WHERE LOREM_IPSUM = TABLE_1.LOREM_IPSUM);

    IF V_TABLE_1_TEST > 0
        THEN
        RETURN;
        ELSE
        INSERT INTO TABLE_1
            SELECT LOREM_IPSUM FROM TABLE(V_EXPENSIVE_RESULT)
            WHERE MOD(LOREM_IPSUM,2) = 0;
    END IF;

END;
/

当 TABLE_1 最初只有一条值为 6 的记录时,这会插入 2 和 4(因为没有共享数据)。

...PL/SQL procedure successfully completed.
SELECT * FROM TABLE_1;
   LOREM_IPSUM
______________
             2
             4
             6

但是如果它在expensive_query 中包含任何内容(例如最初同时包含3 和6),则不会插入任何内容:

...PL/SQL procedure successfully completed.
SELECT * FROM TABLE_1;
   LOREM_IPSUM
______________
             3
             6

【讨论】:

感谢 N. Kaufman 的更新。作为回应,我从这个答案中删除了第二个示例(使用单个语句)。谢谢 谢谢你。我可能需要一段时间才能理解这一点...... EXPENSIVE_QUERY_TYPE IS OBJECT(LOREM_IPSUM NUMBER) - 假设这些参数将成为我昂贵查询的参数。因此,如果我的查询返回 FirstName、LastName、Salary,我的对象是 EXPENSIVE_QUERY_TYPE IS OBJECT(fn varchar(50), ln varchar(50), sal number)。如何用我的“昂贵”查询填充 V_EXPENSIVE_RESULT - 从 emp 中选择 fname、lname、salary,其中薪水 > 12000。插入 V_EXPENSIVE_RESULT(fname,lname,salary) 选择从 emp 中选择 fname,lname,salary > 12000? 谢谢@N.Kaufman 是的,这种方法中的对象类型将匹配expensive_query 标头的形状。如果那是 fname/lname/salary,那么您提供的示例类型定义看起来不错。至于加载它,涉及两部分——选择对象类型和批量收集到表类型。这是一个提炼的语法 SELECT EXPENSIVE_QUERY_TYPE(FNAME, LNAME, SALARY) BULK COLLECT INTO V_EXPENSIVE_RESULT FROM ... JOIN ... WHERE ...;如果有任何问题或后续行动,请告诉我。我也对与 temp table 等人进行性能比较的任何后续行动感兴趣。 感谢您的帮助和耐心。我仍在努力选择对象类型。如果我的查询是 Select fname、lname、salary from emp join sal on emp.dept = sal.dept where sal.salary > 12000,我的批量收集查询会是什么? SELECT EXPENSIVE_QUERY_TYPE(FNAME, LNAME, SALARY) BULK COLLECT INTO V_EXPENSIVE_RESULT FROM emp join sal on emp.dept = sal.dept where sal.salary > 12000。我明白了吗?? 感谢@N.Kaufman 提供了这些表并加入,批量收集看起来不错(尽管通过部门将 emp 加入到 sal 似乎不寻常)。该查询应该可以编译(除此之外),并且可以通过 SELECT FNAME, LNAME, SAL FROM TABLE(V_EXPENSIVE_RESULT) 在以后的选择中使用。谢谢

以上是关于Oracle 使用临时表或其他方法的主要内容,如果未能解决你的问题,请参考以下文章

Spark SQL 2.1 是不是支持将临时表或配置单元表写入 Mysql/Oracle?

显式删除临时表或让SQL Server处理它

sqlserver中判断表或临时表是否存在

在 oracle 中避免全局临时表的方法

一个开发需求的解决方案 & Oracle 临时表介绍

CTE、子查询、临时表或表变量之间是不是存在性能差异?