子查询无法展开的模拟和几个案例
之前生产环境有一部分sql执行出现较大的性能问题,都是由于应该走hash join的走的是filter,而这个问题困扰了小鱼很大一阵子,小鱼是想在sql优化上深入学习的,而为什么子查询没有展开选择走的filter而不是性能更好的hash join了,下面我们先测试,然后再来
之前生产环境有一部分sql执行出现较大的性能问题,都是由于应该走hash join的走的是filter,而这个问题困扰了小鱼很大一阵子,小鱼是想在sql优化上深入学习的,而为什么子查询没有展开选择走的filter而不是性能更好的hash join了,下面我们先测试,然后再来看下生产环境的案例:
数据库版本是10.2.0.4,建立三个表table01、table02、table03
C:\Users\Administrator>sqlplus / as sysdba
SQL*Plus: Release 10.2.0.4.0 - Production on Thu May 15 14:53:07 2014
Copyright (c) 1982, 2007, Oracle. All Rights Reserved.
Connected to:
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL> create table table01 as select * from dba_objects;
SQL> create table table02 as select * from dba_objects;
SQL> create table table03 as select * from dba_objects;
SQL> select * from table02 b where (object_id in (select object_id from table01
a) or object_id in (select object_id from table03));
50038 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 64347382
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4712 | 814K| 154 (2)| 00:00:02 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | TABLE02 | 48330 | 8353K| 154 (2)| 00:00:02 |
|* 3 | TABLE ACCESS FULL | TABLE01 | 512 | 6656 | 2 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL| TABLE03 | 440 | 5720 | 3 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT /*+ */ 0 FROM "TABLE01" "A" WHERE
"OBJECT_ID"=:B1) OR EXISTS (SELECT /*+ */ 0 FROM "TABLE03" "TABLE
03"
WHERE "OBJECT_ID"=:B2))
3 - filter("OBJECT_ID"=:B1)
4 - filter("OBJECT_ID"=:B1)
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
65 recursive calls
0 db block gets
17166265 consistent gets
687 physical reads
0 redo size
2565005 bytes sent via SQL*Net to client
37177 bytes received via SQL*Net from client
3337 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
50038 rows processed
这里看出由于子查询中加了or,cbo只能选择走低性能的filter,而其实这个sql我们改写成如下的形式,此时cbo就能展开这个子查询为表连接
SQL> SELECT *
2 FROM table02 b
3 WHERE object_id IN ( (SELECT object_id
4 FROM table01 a)
5 UNION ALL
6 (SELECT object_id FROM table03));
50038 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3306159213
--------------------------------------------------------------------------------
----------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)|
Time |
--------------------------------------------------------------------------------
----------
| 0 | SELECT STATEMENT | | 95255 | 17M| | 1008 (1)|
00:00:13 |
|* 1 | HASH JOIN | | 95255 | 17M| 2328K| 1008 (1)|
00:00:13 |
| 2 | VIEW | VW_NSO_1 | 95253 | 1209K| | 306 (1)|
00:00:04 |
| 3 | HASH UNIQUE | | 95253 | 1209K| | 306 (51)|
00:00:04 |
| 4 | UNION-ALL | | | | | |
|
| 5 | TABLE ACCESS FULL| TABLE01 | 51209 | 650K| | 153 (1)|
00:00:02 |
| 6 | TABLE ACCESS FULL| TABLE03 | 44044 | 559K| | 153 (1)|
00:00:02 |
| 7 | TABLE ACCESS FULL | TABLE02 | 48330 | 8353K| | 154 (2)|
00:00:02 |
--------------------------------------------------------------------------------
----------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OBJECT_ID"="$nso_col_1")
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
5373 consistent gets
0 physical reads
0 redo size
2565005 bytes sent via SQL*Net to client
37177 bytes received via SQL*Net from client
3337 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
50038 rows processed
我们来看看11.2.0.3下是否也需要改写了,小鱼也没试过,测试下吧:
SQL> select * from table02 b where (object_id in (select object_id from table01
2 a) or object_id in (select object_id from table03));
87289 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1591019701
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 183K| 38M| | 2092 (1)| 00:00:26 |
|* 1 | HASH JOIN | | 183K| 38M| 4472K| 2092 (1)| 00:00:26 |
| 2 | VIEW | VW_NSO_1 | 183K| 2325K| | 677 (1)| 00:00:09 |
| 3 | HASH UNIQUE | | 183K| 2325K| | 677 (51)| 00:00:09 |
| 4 | UNION-ALL | | | | | | |
| 5 | TABLE ACCESS FULL| TABLE03 | 89910 | 1141K| | 338 (1)| 00:00:05 |
| 6 | TABLE ACCESS FULL| TABLE01 | 93256 | 1183K| | 338 (1)| 00:00:05 |
| 7 | TABLE ACCESS FULL | TABLE02 | 82647 | 16M| | 339 (1)| 00:00:05 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OBJECT_ID"="OBJECT_ID")
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
9445 consistent gets
3720 physical reads
0 redo size
4707818 bytes sent via SQL*Net to client
64529 bytes received via SQL*Net from client
5821 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
87289 rows processed
11.2.0.3版本的cbo优化器居然自动把我们这个or查询组合为一个union all然后hash unique去重为一个view视图然后去和主表做hash join,优化器确是在不断的进步。
类似的子查询无法展开的问题我们还可以再看下面几个例子
Oracle 10.2.0.4版本:
SQL> select * from table02 b where object_id in (select ob
ject_id from table01 a where b.object_id>5000);
45120 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 3332700264
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 32 | 5664 | 3182 (1)| 00:00:39 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | TABLE02 | 48330 | 8353K| 154 (2)| 00:00:02 |
|* 3 | FILTER | | | | | |
|* 4 | TABLE ACCESS FULL| TABLE01 | 512 | 6656 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT /*+ */ 0 FROM "TABLE01" "A" WHERE
:B1>5000 AND "OBJECT_ID"=:B2))
3 - filter(:B1>5000)
4 - filter("OBJECT_ID"=:B1)
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
13 recursive calls
0 db block gets
17001967 consistent gets
0 physical reads
0 redo size
2335963 bytes sent via SQL*Net to client
33569 bytes received via SQL*Net from client
3009 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
45120 rows processed
其实这里很可能是个笔误引起的,应该是a.object_id>5000,可能开发人员写成了b.object_id>5000,悲剧的走了filter。
Oracle 11.2.0.3版本:
SQL> SELECT *
2 FROM table02 b
3 WHERE object_id IN (SELECT object_id
4 FROM table01 a
5 WHERE b.object_id > 5000);
82290 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1361234999
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4132 | 887K| 678 (1)| 00:00:09 |
|* 1 | HASH JOIN SEMI | | 4132 | 887K| 678 (1)| 00:00:09 |
|* 2 | TABLE ACCESS FULL | TABLE02 | 4132 | 835K| 338 (1)| 00:00:05 |
| 3 | VIEW | VW_NSO_1 | 91760 | 1164K| 339 (1)| 00:00:05 |
|* 4 | TABLE ACCESS FULL| TABLE01 | 91760 | 1164K| 339 (1)| 00:00:05 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OBJECT_ID"="OBJECT_ID")
2 - filter("B"."OBJECT_ID">5000)
4 - filter("OBJECT_ID">5000)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
32 recursive calls
0 db block gets
8579 consistent gets
2480 physical reads
0 redo size
4466004 bytes sent via SQL*Net to client
60855 bytes received via SQL*Net from client
5487 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
82290 rows processed
可能有朋友提到这里的查询用的是关联列,如果我们用非关联过滤了,其实结果也是一样的
SQL> SELECT *
2 FROM table02 b
3 WHERE object_id IN (SELECT object_id
4 FROM table01 a
5 WHERE b.data_object_id > 5000);
19927 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 1361234999
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 4132 | 887K| 678 (1)| 00:00:09 |
|* 1 | HASH JOIN SEMI | | 4132 | 887K| 678 (1)| 00:00:09 |
|* 2 | TABLE ACCESS FULL | TABLE02 | 4132 | 835K| 339 (1)| 00:00:05 |
| 3 | VIEW | VW_NSO_1 | 93256 | 1183K| 338 (1)| 00:00:05 |
| 4 | TABLE ACCESS FULL| TABLE01 | 93256 | 1183K| 338 (1)| 00:00:05 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OBJECT_ID"="OBJECT_ID")
2 - filter("B"."DATA_OBJECT_ID">5000)
Note
-----
- dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
31 recursive calls
0 db block gets
4491 consistent gets
2480 physical reads
0 redo size
1270866 bytes sent via SQL*Net to client
15128 bytes received via SQL*Net from client
1330 SQL*Net roundtrips to/from client
3 sorts (memory)
0 sorts (disk)
19927 rows processed
这个笔误是常有的事情,或者说开发人员往往写出来的代码只要满足业务逻辑需求,比如小鱼前不久碰见的一个案例也是开发人员写的代码,业务逻辑是满足的,具体代码类似这种查询:
SELECT *
FROM table02 b
WHERE object_id IN (SELECT object_id
FROM table02 a
WHERE b.object_id > 5000);
Execution Plan
----------------------------------------------------------
Plan hash value: 3539933929
-------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
-------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 32 | 5664 | 3182 (1)| 00:00:39 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | TABLE02 | 48330 | 8353K| 154 (2)| 00:00:02 |
|* 3 | FILTER | | | | | |
|* 4 | TABLE ACCESS FULL| TABLE02 | 483 | 6279 | 2 (0)| 00:00:01 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT /*+ */ 0 FROM "TABLE02" "A" WHERE
:B1>5000 AND "OBJECT_ID"=:B2))
3 - filter(:B1>5000)
4 - filter("OBJECT_ID"=:B1)
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
14 recursive calls
0 db block gets
17001959 consistent gets
0 physical reads
0 redo size
2336165 bytes sent via SQL*Net to client
33580 bytes received via SQL*Net from client
3010 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
45121 rows processed
这里由于table02 a和table02 b是同一个表,所以这里业务逻辑完全符合,刚开始数据量小,
他们就一直这么写着用着,慢慢得数量大了,由于是10.2.0.5数据库,后面走filter效率极低,极大的拉低了数据库性能,导致系统宕机,而同样的情况在oracle 11g下优化器却改善了很多。
再来看看下面这个查询,有时候我们需要连接两个表,然后分组求出满足某个列聚合函数的数据
Oracle 10.2.0.4版本:
SQL> select * from table02 b where created
here a.object_id=b.object_id group by a.object_id);
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 1461399523
--------------------------------------------------------------------------------
-
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time
|
--------------------------------------------------------------------------------
-
| 0 | SELECT STATEMENT | | 2 | 354 | 3185 (1)| 00:00:39
|
|* 1 | FILTER | | | | |
|
| 2 | TABLE ACCESS FULL | TABLE02 | 48330 | 8353K| 154 (2)| 00:00:02
|
| 3 | SORT GROUP BY NOSORT| | 512 | 11264 | 2 (0)| 00:00:01
|
|* 4 | TABLE ACCESS FULL | TABLE01 | 512 | 11264 | 2 (0)| 00:00:01
|
--------------------------------------------------------------------------------
-
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CREATED"
"A" WHERE "A"."OBJECT_ID"=:B1 GROUP BY "A"."OBJECT_ID"))
4 - filter("A"."OBJECT_ID"=:B1)
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
37 recursive calls
0 db block gets
34627266 consistent gets
0 physical reads
0 redo size
1139 bytes sent via SQL*Net to client
481 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed
而其实这个sql等价于下面这个sql语句,而走的执行计划是更优秀的hash join
SQL> SELECT *
2 FROM table02 b
3 WHERE created
4 FROM table01 a
5 WHERE a.object_id = b.object_id);
no rows selected
Execution Plan
----------------------------------------------------------
Plan hash value: 1435252230
--------------------------------------------------------------------------------
--------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Ti
me |
--------------------------------------------------------------------------------
--------
| 0 | SELECT STATEMENT | | 2560 | 497K| | 827 (1)| 00
:00:10 |
|* 1 | HASH JOIN | | 2560 | 497K| 1704K| 827 (1)| 00
:00:10 |
| 2 | VIEW | VW_SQ_1 | 51209 | 1100K| | 157 (4)| 00
:00:02 |
| 3 | HASH GROUP BY | | 51209 | 1750K| | 157 (4)| 00
:00:02 |
| 4 | TABLE ACCESS FULL| TABLE01 | 51209 | 1750K| | 153 (1)| 00
:00:02 |
| 5 | TABLE ACCESS FULL | TABLE02 | 48330 | 8353K| | 154 (2)| 00
:00:02 |
--------------------------------------------------------------------------------
--------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - access("OBJECT_ID"="B"."OBJECT_ID")
filter("CREATED"
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
39 recursive calls
0 db block gets
2212 consistent gets
0 physical reads
0 redo size
1139 bytes sent via SQL*Net to client
481 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
7 sorts (memory)
0 sorts (disk)
0 rows processed
oracle 11.2.0.3版本跟10.2.0.4版本也是走的糟糕的filter:
SQL> explain plan for SELECT *
2 FROM table02 b
3 WHERE created
4 FROM table01 a
5 WHERE a.object_id = b.object_id
6 GROUP BY a.object_id);
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 1461399523
---------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 2 | 414 | 5517 (1)| 00:01:07 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL | TABLE02 | 82647 | 16M| 339 (1)| 00:00:05 |
| 3 | SORT GROUP BY NOSORT| | 933 | 20526 | 2 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | TABLE01 | 933 | 20526 | 2 (0)| 00:00:01 |
---------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CREATED"
"A"."OBJECT_ID"=:B1 GROUP BY "A"."OBJECT_ID"))
4 - filter("A"."OBJECT_ID"=:B1)
Note
-----
- dynamic sampling used for this statement (level=2)
22 rows selected.
子查询中包含a.col like b.col的查询
Oracle 10.2.0.4版本:
SQL> SELECT /*+use_hash(a b)*/ *
2 FROM table02 b
3 WHERE object_id IN (SELECT object_id
4 FROM table02 a
5 WHERE a.object_type like b.object_type);
50038 rows selected.
Execution Plan
----------------------------------------------------------
Plan hash value: 337184939
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 177 | 645K (1)| 02:09:02 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL| TABLE02 | 48330 | 8353K| 154 (2)| 00:00:02 |
|* 3 | TABLE ACCESS FULL| TABLE02 | 24 | 576 | 14 (0)| 00:00:01 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT /*+ */ 0 FROM "TABLE02" "A" WHERE
"OBJECT_ID"=:B1 AND "A"."OBJECT_TYPE" LIKE :B2))
3 - filter("OBJECT_ID"=:B1 AND "A"."OBJECT_TYPE" LIKE :B2)
Note
-----
- dynamic sampling used for this statement
Statistics
----------------------------------------------------------
13 recursive calls
0 db block gets
17165439 consistent gets
0 physical reads
0 redo size
2565005 bytes sent via SQL*Net to client
37177 bytes received via SQL*Net from client
3337 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
50038 rows processed
Oracle 11.2.0.3版本
SQL> explain plan for SELECT *
2 FROM table02 b
3 WHERE object_id IN (SELECT object_id
4 FROM table02 a
5 WHERE a.object_type like b.object_type);
Explained.
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
Plan hash value: 337184939
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 207 | 1447K (1)| 04:49:25 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS FULL| TABLE02 | 82647 | 16M| 339 (1)| 00:00:05 |
|* 3 | TABLE ACCESS FULL| TABLE02 | 41 | 984 | 18 (0)| 00:00:01 |
------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter( EXISTS (SELECT 0 FROM "TABLE02" "A" WHERE
"OBJECT_ID"=:B1 AND "A"."OBJECT_TYPE" LIKE :B2))
3 - filter("OBJECT_ID"=:B1 AND "A"."OBJECT_TYPE" LIKE :B2)
Note
-----
- dynamic sampling used for this statement (level=2)
21 rows selected.
这里由于有a.object_type like b.object_type,子查询没有展开,那么是否有办法进行优化了,由于hash join算法决定只能用于等值比较,所以这种a.col like b.col是无法转化为hash join的,如果系统里面真有这种业务需求,那么只能采取别的办法来进行优化了。
上面小鱼简单的列出了子查询无法展开的几个现象和现在比较流行的oracle 10gR2和11gR2版本对于子查询的几个变化。下面小鱼用简短的文章来描述下前些天遇见的几个案例:
1 案例开发人员笔误引起的sql性能问题 http://www.dbaxiaoyu.com/archives/1995
小鱼当初没有过分的去分析为什么最后会走filter,而不走hash join,现在通过上面的几个案例测试,想问题原因基本已经知道了,开发人员有个笔误(其实这个sql也是满足业务需求的,对于开发人员可能不叫笔误)
Select * from abstractti0_
Where abstractti0_.TICKET_ID in ((
Select TICKET_ID from tab02 where。。。)
UNION
(SELECT abstractti8_.TICKET_ID
FROM HF_LT_WORKFLOW_ABSTRACTTICKET abstractti8_
WHERE (abstractti0_.CURRENT_STAGE IN
('xqywtj_deal3', 'xqybcgj_deal3'))
AND (abstractti0_.TICKET_ID IN
(SELECT DISTINCT workitemco0_.ENTITY_ID
FROM HF_LTWORKFLOW_ITEM_COMPLETED workitemco0_
WHERE (workitemco0_.BELONG_TO_ID =
'U00000000805')
AND (workitemco0_.WORKFLOWID =
'xqybcgjWorkflow'))))
由于sql较长,接近100多行,这里为了展示方便,就做了一些改写,基本含义就上面这种,子查询中的又出现了主查询的表的过滤条件,而这个数据库版本正是10.2.0.5版本,这个将导致优化器无法展开子查询为表连接,而不得不选择性能较差的filter,最后改掉abstractti0_为abstractti8_,sql基本在几秒内完成,具体大家可以自己看着上面的测试来进行模拟。
2 or 查询导致子查询无法展开 http://www.dbaxiaoyu.com/archives/2048 选择了错误的filter
AND((abstractti0_.TICKET_ID IN
(SELECT abstractti4_.TICKET_ID
FROM HF_LT_WORKFLOW_ABSTRACTTICKET abstractti4_
WHERE (1 =1 )
AND(abstractti4_.TICKET_ID IN
(SELECT DISTINCT workitemco0_.ENTITY_ID
FROM HF_LTWORKFLOW_ITEM_COMPLETED workitemco0_
WHERE (workitemco0_.BELONG_TO_ID='admin' )
AND(workitemco0_.WORKFLOWID ='x qybcgjWorkflow' )
))
AND(abstractti4_.CURRENT_STAGE='ticket_close' )
))
OR(abstractti0_.TICKET_ID IN
(SELECT DISTINCT abstractti6_.TICKET_ID
FROM HF_LTWORKFLOW_ITEM workitem5_,
HF_LT_WORKFLOW_ABSTRACTTICKET abstractti6_,
HF_DM_SAMPLE dmsample7_
WHERE (1 =1 )
AND(abstractti6_.TICKET_ID IN
(SELECT DISTINCT workitemco0_.ENTITY_ID
FROM HF_LTWORKFLOW_ITEM_COMPLETED workitemco0_
WHERE (workitemco0_.BELONG_TO_ID='admin' )
AND(workitemco0_.WORKFLOWID ='xqybcgjWorkflow' )
))
同样由于sql较长,这些报表的sql都是这么长,数据库版本是10.2.0.5版本,由于or的出现,导致了最后也走了filter,对于这类sql的改写小鱼在上面的测试中也提到了改写为union all即可。
关于sql优化需要大量的经验和对cbo的深入理解,而我们当初学习数据库时就知道一个信息,数据库的性能问题80%来源于不合理的sql,希望小鱼自己在sql优化这个路上有一定的建树
Good luck!
原文地址:子查询无法展开的模拟和几个案例, 感谢原作者分享。

핫 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)

뜨거운 주제











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단계: 로그인 페이지에서 정보를 입력하고 [로그인]을 클릭합니다.

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

애플 휴대폰을 이용하여 개통일을 확인하고 싶다면 휴대폰에 있는 일련번호를 통해 확인하는 것이 가장 좋은 방법이며, 애플 공식 홈페이지를 방문하여 컴퓨터에 연결한 후 세 번째 다운로드를 통해 확인할 수도 있습니다. - 그것을 확인하는 파티 소프트웨어. Apple 휴대폰의 활성화 날짜를 확인하는 방법은 무엇입니까? 답변: 일련번호 쿼리, Apple 공식 웹사이트 쿼리, 컴퓨터 쿼리, 타사 소프트웨어 쿼리 1. 사용자가 휴대폰의 일련번호를 아는 것이 가장 좋습니다. 설정, 일반, 이 기기 정보를 열어 일련번호를 확인할 수 있습니다. 2. 일련번호를 이용하면 휴대폰 개통일뿐만 아니라 휴대폰 버전, 휴대폰 원산지, 휴대폰 공장일 등을 확인할 수 있습니다. 3. 사용자는 Apple의 공식 웹 사이트를 방문하여 기술 지원을 찾고, 페이지 하단의 서비스 및 수리 열을 찾아 거기에서 iPhone 활성화 정보를 확인합니다. 4. 사용자

제목: Oracle을 사용하여 테이블이 잠겨 있는지 쿼리하는 방법은 무엇입니까? Oracle 데이터베이스에서 테이블 잠금은 트랜잭션이 테이블에 쓰기 작업을 수행할 때 다른 트랜잭션이 테이블에 쓰기 작업을 수행하거나 테이블에 구조적 변경(예: 열 추가, 행 삭제)을 수행하려고 할 때 차단된다는 것을 의미합니다. , 등.). 실제 개발 과정에서 관련 문제를 더 잘 해결하고 처리하기 위해 테이블이 잠겨 있는지 쿼리해야 하는 경우가 종종 있습니다. 이 기사에서는 Oracle 문을 사용하여 테이블이 잠겨 있는지 쿼리하는 방법을 소개하고 특정 코드 예제를 제공합니다. 테이블이 잠겨 있는지 확인하려면

포럼은 인터넷에서 가장 일반적인 웹사이트 형태 중 하나입니다. 포럼은 사용자에게 정보를 공유하고 토론을 교환할 수 있는 플랫폼을 제공합니다. Discuz는 일반적으로 사용되는 포럼 프로그램이며 많은 웹마스터들이 이미 이에 대해 매우 잘 알고 있다고 생각합니다. Discuz 포럼을 개발하고 관리하는 동안 분석이나 처리를 위해 데이터베이스의 데이터를 쿼리해야 하는 경우가 종종 있습니다. 이 글에서는 Discuz 데이터베이스의 위치를 쿼리하기 위한 몇 가지 팁을 공유하고 구체적인 코드 예제를 제공합니다. 먼저 Discuz의 데이터베이스 구조를 이해해야 합니다.

Laravel 환경 구성 파일 .env에 대한 일반적인 문제 및 해결 방법 Laravel 프레임워크를 사용하여 프로젝트를 개발할 때 환경 구성 파일 .env에는 데이터베이스 연결 정보, 애플리케이션 키 등과 같은 프로젝트의 주요 구성 정보가 포함되어 있습니다. 그러나 .env 파일을 구성할 때 몇 가지 일반적인 문제가 있는 경우가 있습니다. 이 문서에서는 이러한 문제를 소개하고 해결 방법을 제공하며 참조용 특정 코드 예제를 첨부합니다. 문제 1: .env 파일을 구성했는데 .env 파일을 읽을 수 없습니다.

BitTorrent 코인(BTT)의 최신 가격을 확인하세요. BTT는 파일 공유 및 다운로드에 대해 BitTorrent 네트워크 사용자에게 보상하는 데 사용되는 TRON 블록체인의 암호화폐입니다. BTT의 최신 가격을 찾는 방법은 다음과 같습니다. 신뢰할 수 있는 가격 확인 웹사이트나 앱을 선택하세요. 일반적으로 사용되는 가격 쿼리 웹사이트는 다음과 같습니다: CoinMarketCap: https://coinmarketcap.com/Coindesk: https://www.coindesk.com/Binance: https://www.binance.com/ 웹사이트나 앱 BTT에서 검색하세요. BTT의 최신 가격을 확인하세요. 참고: 암호화폐 가격
