我在ORACLE 11g
:
STRONG
和WEAK
的表。WEAK
的主键是由STRONG
的主键(称为pk
)加上一个附加列(称为fk
)组成的复合词。1:N
关系。N
条目相关的WEAK
STRONG
行中始终只有一行具有特殊关系。1:1
列添加到fk
也可以实现额外的STRONG
关系。整体情况如下:
现在,我必须定义一个视图,其中显示STRONG
行以及由1:1
关系链接的一些其他列。我尝试了两种基本方法:
SELECT
(SELECT some_data1 FROM weak WHERE weak.pk = strong.pk AND weak.fk = strong.fk) some_data1,
(SELECT some_data2 FROM weak WHERE weak.pk = strong.pk AND weak.fk = strong.fk) some_data2
FROM strong
SELECT
weak.some_data1,
weak.some_data2
FROM strong
LEFT OUTER JOIN weak ON weak.pk = strong.pk AND weak.fk = strong.fk
我首先认为"左外连接" -way必须更好,我仍然认为只要没有WHERE/ORDER_BY
- 条款就是这样。但是,在现实世界的应用程序中,用户查询对话框输入是动态的
翻译成上述陈述的扩展。通常,用户知道STRONG
的主键,导致这样的查询:
SELECT *
FROM the_view
WHERE the_view.pk LIKE '123%' --Or even the exact key
ORDER BY the_view.pk
使用"左外连接" -way,我们遇到了一些非常严重的性能问题,即使这些SELECT
中的大多数只返回几行。我认为发生的事情是哈希表不适合
记忆导致太多I/O
- 事件。因此,我们回到了Subselects。
现在,我有几个问题:
Oracle是否必须为每个SELECT
计算整个哈希表(使用ORDER_BY
)?
为什么" Subselect" - 更快?在这里,值得注意的是,这些列也可以出现在WHERE
- 子句中。
加入这两个表是否有可能增加选择行的数量?如果是这样的话:我们可以告诉Oracle,从逻辑角度看这种情况永远不会发生吗?
如果"左外连接" -Way不是一个表现良好的选项:" Subselect" -way似乎有点多余。还有更好的方法吗?
非常感谢!
根据要求,我将添加实际案例的解释计划。但是,这里有一些重要的事情:
STRONG => WEAK
- 加入嵌套连接时(见下文)。实际情况如下:
ZV
是我们目标视图的名称 - 下面的解释计划是指该视图。Z
(~3M行)加入T
(~1M行)T
加入CCPP
(约1M行)TV
是基于T
的视图。来想一想......这可能很关键。前端应用程序限制了我们定义这些视图的方式:在ZV
中,我们必须加入TV
而不是T
,我们无法实现T => CCPP
-join TV
,强制我们将连接TV => CCPP
定义为嵌套连接。---------------------------------------------------------------------------- ----------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|
---------------------------------------------------------------------------- ----------------------------------
| 0 | SELECT STATEMENT | | 717K| 73M| | 13340 (2)|
| 1 | HASH JOIN OUTER | | 717K| 73M| 66M| 13340 (2)|
| 2 | VIEW | | 687K| 59M| | 5 (0)|
| 3 | NESTED LOOPS OUTER | | 687K| 94M| | 5 (0)|
| 4 | NESTED LOOPS OUTER | | 1 | 118 | | 4 (0)|
| 5 | TABLE ACCESS BY INDEX ROWID | Z | 1 | 103 | | 3 (0)|
| 6 | INDEX UNIQUE SCAN | SYS_C00245876 | 1 | | | 2 (0)|
| 7 | INDEX UNIQUE SCAN | SYS_C00245876 | 1798K| 25M| | 1 (0)|
| 8 | VIEW PUSHED PREDICATE | TV | 687K| 17M| | 1 (0)|
| 9 | NESTED LOOPS OUTER | | 1 | 67 | | 2 (0)|
| 10 | TABLE ACCESS BY INDEX ROWID| T | 1 | 48 | | 2 (0)|
| 11 | INDEX UNIQUE SCAN | SYS_C00245609 | 1 | | | 1 (0)|
| 12 | INDEX UNIQUE SCAN | SYS_C00254613 | 1 | 19 | | 0 (0)|
| 13 | TABLE ACCESS FULL | CCPP | 5165K| 88M| | 4105 (3)|
--------------------------------------------------------------------------------------------------------------
答案 0 :(得分:1)
真实问题是 - 您的查询返回了多少条记录?
仅10条记录或10.000(或10M),您希望快速查看前10行?
对于字母大小写,子查询解决方案确实更好,因为您不需要排序,只需少量查找WEAK表。
对于以前的情况(即两个表中所选行的数量都很小)我希望执行计划如下:
--------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4 | 336 | 100 (1)| 00:00:02 |
| 1 | SORT ORDER BY | | 4 | 336 | 100 (1)| 00:00:02 |
| 2 | NESTED LOOPS OUTER | | 4 | 336 | 99 (0)| 00:00:02 |
| 3 | TABLE ACCESS BY INDEX ROWID| STRONG | 4 | 168 | 94 (0)| 00:00:02 |
|* 4 | INDEX RANGE SCAN | STRONG_IDX | 997 | | 4 (0)| 00:00:01 |
| 5 | TABLE ACCESS BY INDEX ROWID| WEAK | 1 | 42 | 2 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | WEAK_IDX | 1 | | 1 (0)| 00:00:01 |
--------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("STRONG"."PK" LIKE '1234%')
filter("STRONG"."PK" LIKE '1234%')
6 - access("WEAK"."PK"(+)="STRONG"."PK" AND "WEAK"."FK"(+)="STRONG"."FK")
filter("WEAK"."PK"(+) LIKE '1234%')
如果您在一个或另一个表上看到FULL TABLE SCAN - 优化展示可能是谓词 pk LIKE' 123%' 将返回太多记录和索引访问速度会慢一些。 这可能是一个好的或坏的猜测,因此您可能需要检查您的表统计和基数估计。
以下是一些其他信息
<强> Q1 强>
如果Oracle执行 HASH JOIN ,则必须在内存中读取整个数据源(通常是较小的数据源) 在哈希表中。这是整个表或它的一部分,由WHERE / ON子句过滤 (在您的情况下,只有pk LIKE&#39; 123%&#39;)
的记录<强> Q2 强>
这可能只是一种印象,因为您很快就会看到第一条记录。子查询被执行 仅适用于前几个获取的行。
要知道必须检查(或发布)执行计划的确切答案。
<强> Q3 强>
不,抱歉,加入这两个表永远不会增加选择的行数但是返回确切的行数 如SQL标准中所定义。
您有责任在唯一/主键上定义连接以避免重复。
第四季度
您当然可以在子查询中选择some_data1 ||'#'||some_data2
之类的内容,但这是您的责任
判断它是否安全..