包含union all的view子查询无法展开表连接的模拟
之前小鱼写过一些关于子查询无法展开的文章,其中主要涉及到以下几点: 1关联的列没有not null约束,在子查询中使用not in去查找(oracle 10g无法展开为子查询,oracle 11g由于有新的hash join算法已经可以),如下 SQL> select a.* from ta01 a where a.obj
之前小鱼写过一些关于子查询无法展开的文章,其中主要涉及到以下几点:<br>
1关联的列没有not null约束,在子查询中使用not in去查找(oracle 10g无法展开为子查询,oracle 11g由于有新的hash join算法已经可以),如下
SQL> select a.* from ta01 a where a.object_id not in (select b.object_id from ta02 b)
Ta01和ta02表的object_id列上没有not null的约束
2 子查询中包含主表的关联列的谓词过滤(oracle 10g也无法展开为子查询,oracle 11g可以展开为子查询),如下
SQL> select a.* from ta01 a where a.object_id in (select b.object_id from ta02 b where a.object_type=’TABLE’);
3 子查询中包含有下列形式的or的查询(oracle 10g同样无法展开为子查询,oracle 11g可以展开)
SQL> select a.* from ta01 a where a.object_id in (select b.object_id from ta02 b
where object_type='TABLE') or a.object_id in (select c.object_id from ta02 c wh
ere c.object_type='INDEX');
4 子查询包含有主表和子表列的like关联,比如下列sql语句(oracle 10g和11g都无法展开为子查询)
SQL> select a.* from ta01 a where a.object_id in (select b.object_id from ta02 b
where a.data_object_id like b.data_object_id);
http://www.eygle.com/archives/2013/04/2013_oracle_dtcc_dbsnake.html
eygle这篇文章里面又提到了一个比较常见的子查询无法展开的case,借鉴作者的案例进行一点简单的模拟来进行验证。
SQL> select * from v$version;
BANNER
----------------------------------------------------------------
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bi
PL/SQL Release 10.2.0.4.0 - Production
CORE 10.2.0.4.0 Production
TNS for 64-bit Windows: Version 10.2.0.4.0 - Production
NLSRTL Version 10.2.0.4.0 - Production
SQL> create table ta01 as select * from dba_objects;
Table created.
SQL> create table ta02 as select * from dba_objects;
Table created.
SQL> create table tb01 as select * from dba_objects;
Table created.
SQL> create table tb02 as select * from dba_objects;
Table created.
SQL> create view ta_view as
2 select object_id,data_object_id,object_type from ta01 union all
3 select object_id,data_object_id,object_type from ta02;
View created.
SQL> create view tb_view as
2 select object_id,data_object_id,object_type from tb01 union all
3 select object_id,data_object_id,object_type from tb02;
View created.
SQL> select a.* from ta_view a where a.object_id in (select b.object_id from tb_
view b where b.object_type='TABLE');
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
------------------------------------------------------------
Plan hash value: 3623909176
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3738K| 131M| 617 (1)| 00:00:08 |
|* 1 | FILTER | | | | | |
| 2 | VIEW | TA_VIEW | 88401 | 3194K| 308 (1)| 00:00:04 |
| 3 | UNION-ALL | | | | | |
| 4 | TABLE ACCESS FULL| TA01 | 42509 | 1535K| 154 (1)| 00:00:02 |
| 5 | TABLE ACCESS FULL| TA02 | 45892 | 1658K| 154 (1)| 00:00:02 |
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
------------------------------------------------------------
| 6 | VIEW | TB_VIEW | 42 | 1008 | 309 (1)| 00:00:04 |
| 7 | UNION-ALL | | | | | |
|* 8 | TABLE ACCESS FULL| TB01 | 17 | 408 | 154 (1)| 00:00:02 |
|* 9 | TABLE ACCESS FULL| TB02 | 25 | 600 | 154 (1)| 00:00:02 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT /*+ */ 0 FROM ( (SELECT /*+ */
"OBJECT_ID" "OBJECT_ID","DATA_OBJECT_ID" "DATA_OBJECT_ID","OBJECT_
TYPE"
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
------------------------------------------------------------
"OBJECT_TYPE" FROM SYS."TB01" "TB01" WHERE "OBJECT_ID"=:B1 AND
"OBJECT_TYPE"='TABLE') UNION ALL (SELECT /*+ */ "OBJECT_ID"
"OBJECT_ID","DATA_OBJECT_ID" "DATA_OBJECT_ID","OBJECT_TYPE"
"OBJECT_TYPE" FROM SYS."TB02" "TB02" WHERE "OBJECT_ID"=:B2 AND
"OBJECT_TYPE"='TABLE')) "B"))
8 - filter("OBJECT_ID"=:B1 AND "OBJECT_TYPE"='TABLE')
9 - filter("OBJECT_ID"=:B1 AND "OBJECT_TYPE"='TABLE')
Note
-----
- dynamic sampling used for this statement
33 rows selected.
Statistics
----------------------------------------------------------
146 recursive calls
0 db block gets
136371691 consistent gets
0 physical reads
0 redo size
83259 bytes sent via SQL*Net to client
2868 bytes received via SQL*Net from client
218 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3247 rows processed
这里由于主查询和子查询的表都是两个表相关联的视图,这个导致in之后的括号内的子查询并不是一个常量的集合,所以oracle这里没有对该子查询展开为表连接。
而我们可以改写为下列的sql语句,但是这里好像结果集不一样,这个是因为我们选取的表不是1对1引起的,这个不在我们考虑的范围内。
SQL> SELECT a.*
2 FROM ta_view a,
3 (SELECT object_id
4 FROM tb_view
5 WHERE object_type = 'TABLE') b
6 WHERE a.object_id = b.object_id;
6494 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 48097912
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3328K| 158M| 640 (5)| 00:00:08 |
|* 1 | HASH JOIN | | 3328K| 158M| 640 (5)| 00:00:08 |
| 2 | VIEW | TB_VIEW | 3306 | 42978 | 309 (1)| 00:00:04 |
| 3 | UNION-ALL | | | | | |
|* 4 | TABLE ACCESS FULL| TB01 | 1756 | 24584 | 154 (1)| 00:00:02 |
|* 5 | TABLE ACCESS FULL| TB02 | 1550 | 21700 | 154 (1)| 00:00:02 |
| 6 | VIEW | TA_VIEW | 100K| 3637K| 308 (1)| 00:00:04 |
| 7 | UNION-ALL | | | | | |
| 8 | TABLE ACCESS FULL| TA01 | 50333 | 786K| 154 (1)| 00:00:02 |
| 9 | TABLE ACCESS FULL| TA02 | 50334 | 786K| 154 (1)| 00:00:02 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."OBJECT_ID"="OBJECT_ID")
4 - filter("OBJECT_TYPE"='TABLE')
5 - filter("OBJECT_TYPE"='TABLE')
Statistics
----------------------------------------------------------
1083 recursive calls
0 db block gets
3412 consistent gets
2782 physical reads
196 redo size
139022 bytes sent via SQL*Net to client
5244 bytes received via SQL*Net from client
434 SQL*Net roundtrips to/from client
31 sorts (memory)
0 sorts (disk)
6494 rows processed
当然如果业务也是1对多,那么这个改写是不符合业务逻辑的,那么是否就不能进行改写了,其实也不是这样的,我们只需要在构造的这个表中加上一个distinct去掉b表的重复的值,这样不就是类似为半连接了吗。
SQL> SELECT a.*
2 FROM ta_view a,
3 (SELECT distinct object_id
4 FROM tb_view
5 WHERE object_type = 'TABLE') b
6 WHERE a.object_id = b.object_id;
3247 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1607119383
--------------------------------------------------------------------------------
--
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
--
| 0 | SELECT STATEMENT | | 3328K| 158M| 642 (5)| 00:00:08
|
|* 1 | HASH JOIN | | 3328K| 158M| 642 (5)| 00:00:08
|
| 2 | VIEW | | 3306 | 42978 | 310 (2)| 00:00:04
|
| 3 | HASH UNIQUE | | 3306 | 42978 | 310 (2)| 00:00:04
|
| 4 | VIEW | TB_VIEW | 3306 | 42978 | 309 (1)| 00:00:04
|
| 5 | UNION-ALL | | | | |
|
|* 6 | TABLE ACCESS FULL| TB01 | 1756 | 24584 | 154 (1)| 00:00:02
|
|* 7 | TABLE ACCESS FULL| TB02 | 1550 | 21700 | 154 (1)| 00:00:02
|
| 8 | VIEW | TA_VIEW | 100K| 3637K| 308 (1)| 00:00:04
|
| 9 | UNION-ALL | | | | |
|
| 10 | TABLE ACCESS FULL | TA01 | 50333 | 786K| 154 (1)| 00:00:02
|
| 11 | TABLE ACCESS FULL | TA02 | 50334 | 786K| 154 (1)| 00:00:02
|
--------------------------------------------------------------------------------
--
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."OBJECT_ID"="B"."OBJECT_ID")
6 - filter("OBJECT_TYPE"='TABLE')
7 - filter("OBJECT_TYPE"='TABLE')
Statistics
----------------------------------------------------------
15 recursive calls
0 db block gets
3007 consistent gets
0 physical reads
0 redo size
83259 bytes sent via SQL*Net to client
2868 bytes received via SQL*Net from client
218 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
3247 rows processed
关于我们常见的select a.* from a,b where a.id=b.id和select a.* from a where a.id in (select b.id from b)这两种查询,在业务层面有不同的是如果b表没有重复的id,那么这个查询业务逻辑是相同的,而如果b表有重复的,子查询是hash join的半连接方式,会对b.id进行去重,所以如果b.id存在多个重复值,可能会引起查询结果不一致。
并不是说包含union all的veiw会引起子查询无法展开为表连接,如上单个union all的view是不会影响子查询展开为表连接的。
SQL> select a.* from ta01 a where a.object_id in (select b.object_id from tb_vie
w b where b.object_type='TABLE');
1623 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1785931674
--------------------------------------------------------------------------------
--
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
--
| 0 | SELECT STATEMENT | | 1 | 190 | 464 (2)| 00:00:06
|
|* 1 | HASH JOIN RIGHT SEMI | | 1 | 190 | 464 (2)| 00:00:06
|
| 2 | VIEW | VW_NSO_1 | 4229 | 54977 | 309 (1)| 00:00:04
|
| 3 | VIEW | TB_VIEW | 4229 | 99K| 309 (1)| 00:00:04
|
| 4 | UNION-ALL | | | | |
|
|* 5 | TABLE ACCESS FULL| TB01 | 1692 | 40608 | 154 (1)| 00:00:02
|
|* 6 | TABLE ACCESS FULL| TB02 | 2537 | 60888 | 154 (1)| 00:00:02
|
| 7 | TABLE ACCESS FULL | TA01 | 42509 | 7347K| 154 (1)| 00:00:02
|
--------------------------------------------------------------------------------
--
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."OBJECT_ID"="$nso_col_1")
5 - filter("OBJECT_TYPE"='TABLE')
6 - filter("OBJECT_TYPE"='TABLE')
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
53 recursive calls
0 db block gets
3166 consistent gets
0 physical reads
0 redo size
85130 bytes sent via SQL*Net to client
1680 bytes received via SQL*Net from client
110 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
1623 rows processed
而如果我们换到oracle 11.2.0.1的版本,再来看看包含两个union all的view的子查询是否能够展开
SQL> select * from v$version;
BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
PL/SQL Release 11.2.0.1.0 - Production
CORE 11.2.0.1.0 Production
TNS for Linux: Version 11.2.0.1.0 - Production
NLSRTL Version 11.2.0.1.0 – Production
SQL> select a.* from ta_view a where a.object_id in (select b.object_id from tb_view b where b.object_type='TABLE');
7629 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1656093151
-----------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-----------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6779K| 323M| 1206 (4)| 00:00:15 |
|* 1 | HASH JOIN | | 6779K| 323M| 1206 (4)| 00:00:15 |
| 2 | VIEW | VW_NSO_1 | 4191 | 54483 | 586 (1)| 00:00:08 |
| 3 | HASH UNIQUE | | 4191 | 54483 | 586 (1)| 00:00:08 |
| 4 | VIEW | TB_VIEW | 4191 | 54483 | 585 (1)| 00:00:08 |
| 5 | UNION-ALL | | | | | |
|* 6 | TABLE ACCESS FULL| TB01 | 2036 | 48864 | 293 (1)| 00:00:04 |
|* 7 | TABLE ACCESS FULL| TB02 | 2155 | 51720 | 292 (1)| 00:00:04 |
| 8 | VIEW | TA_VIEW | 161K| 5845K| 585 (1)| 00:00:08 |
| 9 | UNION-ALL | | | | | |
| 10 | TABLE ACCESS FULL | TA01 | 82194 | 2969K| 292 (1)| 00:00:04 |
| 11 | TABLE ACCESS FULL | TA02 | 79581 | 2875K| 292 (1)| 00:00:04 |
-----------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("A"."OBJECT_ID"="OBJECT_ID")
6 - filter("OBJECT_TYPE"='TABLE')
7 - filter("OBJECT_TYPE"='TABLE')
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
63 recursive calls
0 db block gets
5917 consistent gets
3072 physical reads
0 redo size
200965 bytes sent via SQL*Net to client
6108 bytes received via SQL*Net from client
510 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
7629 rows processed
这里oracle选择了将子查询展开为了表连接,优化器确实在做着很多的改变,这些改变需要我们通过文档 测试用例和实际的案例来验证,可以这么说脱离了oracle的版本来谈性能优化 sql调优其实往往是不严谨的。
最近注册了朋友介绍的一个论坛 http://www.bi168.cn/forum.php ,之前也注册了很多论坛比如itpub、otn、ask maclean等等,都没有怎么过多的去关注论坛的东西,记得maclean liu说过每天能遇见的案例是有限的,但是网络的同行遇见的case确是很多的,如果能够将别人遇见的模拟 理解 解决那么这个就是自己的。
原文地址:包含union all的view子查询无法展开表连接的模拟, 感谢原作者分享。

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제











Keep 체지방 측정기 연결 방법 Keep에는 특별히 고안된 체지방 측정기가 있지만 대부분의 사용자는 Keep 체지방 측정기 연결 방법을 모릅니다. 다음은 Keep 체지방 측정기 연결 방법에 대한 그래픽 튜토리얼입니다. 편집자가 사용자에게 제공합니다. 관심 있는 사용자가 와서 살펴보세요! Keep 체지방 측정기 연결 방법 1. 먼저 Keep 소프트웨어를 열고 메인 페이지로 이동하여 오른쪽 하단에 있는 [내]를 클릭하여 [스마트 하드웨어]를 선택합니다. 2. 그런 다음 내 스마트 장치 페이지에서 중앙의 [기기 추가] 버튼을 클릭한 후 인터페이스를 추가하려는 기기를 선택하고 [스마트 체지방/체중 측정기]를 선택합니다. 4. 그런 다음 기기 모델 선택 페이지에서 [체지방 측정기 유지] 옵션을 클릭합니다. 5. 마지막으로 아래 표시된 인터페이스에서 마지막으로 하단에 [지금 추가]를 선택합니다.

12306 티켓 예매 앱의 최신 버전을 다운로드하세요. 모두가 매우 만족하는 여행 티켓 구매 소프트웨어입니다. 소프트웨어에서 제공되는 다양한 티켓 소스가 있어 매우 편리합니다. - 실명인증으로 온라인 구매가 가능합니다. 모든 사용자가 쉽게 여행티켓과 항공권을 구매하고 다양한 할인 혜택을 누릴 수 있습니다. 또한 사전에 예약하고 티켓을 얻을 수도 있습니다. 호텔을 예약하거나 차량으로 픽업 및 하차할 수도 있습니다. 한 번의 클릭으로 원하는 곳으로 이동하고 티켓을 구매할 수 있어 여행이 더욱 간편해지고 편리해집니다. 모든 사람의 여행 경험이 더욱 편안해졌습니다. 이제 편집자가 온라인으로 자세히 설명합니다. 12306명의 사용자에게 과거 티켓 구매 기록을 볼 수 있는 방법을 제공합니다. 1. 철도 12306을 열고 오른쪽 하단의 My를 클릭한 후 My Order를 클릭합니다. 2. 주문 페이지에서 Paid를 클릭합니다. 3. 유료페이지에서

Xuexin.com에서 내 학업 자격을 어떻게 확인하나요? Xuexin.com에서 학업 자격을 확인할 수 있습니다. 많은 사용자가 Xuexin.com에서 학업 자격을 확인하는 방법을 모릅니다. 다음으로 편집자는 Xuexin.com에서 학업 자격을 확인하는 방법에 대한 그래픽 튜토리얼을 제공합니다. 유저들이 와서 구경해 보세요! Xuexin.com 사용 튜토리얼: Xuexin.com에서 학업 자격을 확인하는 방법 1. Xuexin.com 입구: https://www.chsi.com.cn/ 2. 웹사이트 쿼리: 1단계: Xuexin.com 주소를 클릭합니다. 위의 홈페이지에 들어가려면 [교육 쿼리]를 클릭합니다. 2단계: 최신 웹페이지에서 아래 그림의 화살표와 같이 [쿼리]를 클릭합니다. 3단계: 새 페이지에서 [학점 파일에 로그인]을 클릭합니다. 4단계: 로그인 페이지에서 정보를 입력하고 [로그인]을 클릭합니다.

Edge 브라우저를 사용하여 웹 페이지에 액세스할 때 연결이 전용 연결이 아니어서 웹 탐색이 실패한다는 메시지가 표시된 적이 있습니까? 어떻게 진행되고 있나요? 많은 친구들이 이 문제를 해결하는 방법을 모릅니다. 다음 세 가지 해결 방법을 살펴볼 수 있습니다. 방법 1(간단하고 투박함): 엣지 브라우저에서 설정에 들어가 보안 기능을 끄고, 웹사이트 권한에서 위치 접근권한을 차단하는 방법으로 웹사이트 접속이 불가능한 문제를 해결해 볼 수 있습니다. 이 접근법의 효과와 기간은 다양할 수 있으며 구체적인 효과를 확인할 수 없다는 점에 유의하는 것이 중요합니다. 브라우저를 다시 시작한 후 웹사이트를 방문하여 문제가 해결되었는지 확인할 수 있습니다. 방법 2: 키보드를 영어 입력으로 조정

1. 이어폰을 이어폰 상자에 넣고 뚜껑을 열어둔 상태로 상자의 버튼을 길게 눌러 이어폰 페어링 상태로 들어갑니다. 2. 음악 감상 기능을 켜고 블루투스 헤드폰을 선택하거나, 시계 설정 기능에서 블루투스 헤드폰을 선택하세요. 3. 성공적으로 페어링하려면 시계에서 헤드셋을 선택하세요.

블루투스 컨트롤러를 Gohan Arcade에 연결하는 방법은 무엇입니까? 손오공 게임센터는 많은 모바일 게임 플레이어들이 사용하는 게임 박스로, 다수의 인기 게임 리소스와 풍부한 게임 관련 기능을 담고 있습니다. 아래에서는 게임 컨트롤러 연결 방법을 소개하겠습니다. 1. 먼저 Gohan Game Center APP 홈페이지로 이동한 후 홈페이지 오른쪽 하단에 있는 "내" 옵션을 클릭합니다. 2. 내 페이지에서 [컨트롤러] 기능을 찾으면 위치가 그림에 표시됩니다. 3. 선택하여 켜십시오. 휴대폰의 Bluetooth 기능의 경우 컨트롤러의 전원이 켜져 있는지 확인하십시오. 4. 마지막으로 컨트롤러의 지침에 따라 일치하는 연결을 만드십시오. 접속에 성공하면 모바일 게임을 이용하여 다양한 게임을 체험할 수 있습니다.

MySQL과 PL/SQL은 각각 관계형 데이터베이스와 절차적 언어의 특성을 나타내는 서로 다른 두 가지 데이터베이스 관리 시스템입니다. 이 기사에서는 구체적인 코드 예제를 통해 MySQL과 PL/SQL 간의 유사점과 차이점을 비교합니다. MySQL은 SQL(구조적 쿼리 언어)을 사용하여 데이터베이스를 관리하고 운영하는 인기 있는 관계형 데이터베이스 관리 시스템입니다. PL/SQL은 Oracle 데이터베이스 고유의 절차적 언어로 저장 프로시저, 트리거, 함수 등의 데이터베이스 개체를 작성하는 데 사용됩니다. 같은

Keep을 Huawei 팔찌에 연결하는 방법 Keep 소프트웨어에서 Huawei 팔찌를 연결할 수 있습니다. 대부분의 사용자는 Huawei 팔찌를 연결하는 방법을 모릅니다. 다음은 편집자가 가져온 Huawei 팔찌에 연결하는 방법에 대한 그래픽 튜토리얼입니다. 그리고 한번 보세요! Keep을 Huawei 팔찌에 연결하는 방법 1. 먼저 Keep 애플리케이션을 열고 메인 페이지 오른쪽 하단의 [Me]를 클릭하여 특수 영역으로 들어간 후 [Smart Hardware]를 선택합니다. 2. 그런 다음 내 스마트 장치에 도전합니다. 기능 페이지를 클릭하고 중앙에 있는 [장치 추가]를 클릭합니다. 3. 그런 다음 추가하려는 장치를 선택하는 페이지에서 [스마트 팔찌/시계] 기능을 선택합니다. 4. 마지막으로 아래 표시된 인터페이스에서 연결할 화웨이 시계 모델.
