我有这样的查询:
SELECT * FROM TEST1 LEFT OUTER JOIN TEST2 on TEST1.ID=TEST2.ID
UNION ALL
SELECT * FROM TEST3 LEFT OUTER JOIN TEST4 on TEST3.ID=TEST4.ID;
我在这里看到的行为是,它首先连接TEST1和TEST2表(数十亿行),然后将输出存储在temp表空间中。然后它将TEST3和TEST4连接起来,然后将输出保存在相同的临时表中。最后从那里选择记录以显示结果。
我在Redshift和Oracle中都看到了这种行为。我只是想知道为什么从第一个SELECT获得结果后为什么将结果存储在临时段中。是时候占用和占用临时空间了。它不能只是在第一个SELECT完成后才开始显示结果,然后进入第二个(而不是存储)。
答案 0 :(得分:0)
这个答案有些投机,因为我没有Oracle文档参考。通过检查,我们可以想象您想运行以下查询:
SELECT * FROM TEST1 JOIN TEST2
UNION ALL
SELECT * FROM TEST3 JOIN TEST4
ORDER BY some_col;
很明显,要应用诸如ORDER BY
之类的任何设置操作,从联合查询返回的所有记录都必须放在一个逻辑位置。临时表似乎可以工作。
您不是在使用ORDER BY
似乎不会影响Oracle正在使用的工作流程。
我还可以添加Oracle坚持使用临时表的另一个原因。假设有可能将联合的两个半部分直接写入缓冲区。但是,如果以后总联合查询的大小突然超过缓冲区可以容纳的大小,会发生什么情况呢?答案是您的数据库将崩溃。因此,使用临时表是一个安全的选择,通常应该总是有效。
答案 1 :(得分:0)
您如何观察这种行为?您有没有机会执行INSERT
或CREATE TABLE
?那将解释您的观察,因为最后,所有行都是必需的。
此外,如果您的客户设置了选项fetch all rows
,则可以观察到这一点。
但是在通常情况下,当客户对前几行不感兴趣 Oracle快速返回第一个联接中的第一个可用行(数组大小)时,会忽略第二个
您可以执行这个小小的Gedanken实验:
create table test1 as
select rownum id,
lpad('x',1023,'X') pad
from dual connect by level <= 1000000;
在表2至4中创建模拟。
现在运行查询(适应有效语法)
SELECT * FROM TEST1 CROSS JOIN TEST2
UNION ALL
SELECT * FROM TEST3 CROSS JOIN TEST4;
这将在大约30秒内返回我在SQL Developer中的第一页,从而以某种方式驳斥了您的主张。
简单地计算出两个10 ** 6 * 10 ** 6笛卡尔式行长为1K的所需TEMP空间-这远高于我的TEMP配置。
观察 Oracle实际情况的一种可能方法是使用/*+ gather_plan_statistics */
提示运行查询。
比得到语句的SQL_ID
并检查计划中的实际行A-Rows
select * from table(dbms_xplan.display_cursor('a9y62gxagups6',null,'ALLSTATS LAST'));
SQL_ID a9y62gxagups6, child number 0
-------------------------------------
SELECT /*+ gather_plan_statistics */ * FROM TEST1 CROSS JOIN TEST2
UNION ALL SELECT * FROM TEST3 CROSS JOIN TEST4
Plan hash value: 1763392637
--------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads | Writes | OMem | 1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 50 |00:00:28.52 | 166K| 166K| 142K| | | |
| 1 | UNION-ALL | | 1 | | 50 |00:00:28.52 | 166K| 166K| 142K| | | |
| 2 | MERGE JOIN CARTESIAN| | 1 | 1000G| 50 |00:00:28.52 | 166K| 166K| 142K| | | |
| 3 | TABLE ACCESS FULL | TEST1 | 1 | 1000K| 1 |00:00:00.02 | 4 | 28 | 0 | | | |
| 4 | BUFFER SORT | | 1 | 1000K| 50 |00:00:28.49 | 166K| 166K| 142K| 1255M| 11M| 97M (0)|
| 5 | TABLE ACCESS FULL | TEST2 | 1 | 1000K| 1000K|00:00:03.66 | 166K| 166K| 0 | | | |
| 6 | MERGE JOIN CARTESIAN| | 0 | 1000G| 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 7 | TABLE ACCESS FULL | TEST3 | 0 | 1000K| 0 |00:00:00.01 | 0 | 0 | 0 | | | |
| 8 | BUFFER SORT | | 0 | 1000K| 0 |00:00:00.01 | 0 | 0 | 0 | 1103M| 10M| |
| 9 | TABLE ACCESS FULL | TEST4 | 0 | 1000K| 0 |00:00:00.01 | 0 | 0 | 0 | | | |
--------------------------------------------------------------------------------------------------------------------------------------
您看到的是Oracle
1)完全扫描了表格2(第5行)
2)从表1中获得一行(第3行)
3)返回第50行(第0行)
4)表3和4未分配(第7和9行)
您可以简单地将示例适应于内部联接,以查看相似的结果。