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 不需要);有条件的INSERT
或MERGE
可能就足够了。另外,您要处理多少数据?这是数百/数千,还是数百万(您是否尝试过仅将其保存在内存中?)
当然,感谢您的回复。我首先使用结果集(这是一个复杂且有点昂贵的查询,因此想要存储结果)来比较表 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 使用临时表或其他方法的主要内容,如果未能解决你的问题,请参考以下文章