[20181220]使用提示OR_EXPAND优化.txt
[20181220]使用提示OR_EXPAND优化.txt
--//链接http://www.itpub.net/thread-2107240-2-1.html,http://www.itpub.net/thread-2107231-2-1.html的讨论.
--//ZALBB建议在18c下尝试看看,我们这里仅仅1台18c,而且还是生产系统,正好前几天在办公机器重新安装12c,在12c测试看看.
--//主要问题感觉oracle对于这样的sql有点奇怪....
1.环境:
SCOTT@test01p> @ ver1
PORT_STRING VERSION BANNER CON_ID
------------------------------ -------------- -------------------------------------------------------------------------------- ----------
IBMPC/WIN_NT64-9.1.0 12.2.0.1.0 Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production 0
create table t1 as select rownum id1 ,rownum id2 ,lpad('x',100,'x') name from dual connect by level<=6000;
create table t2 as select rownum id1 ,rownum id2 ,lpad('x',100,'x') name from dual connect by level<=6000;
create index i_t1_id1 on t1(id1);
create index i_t1_id2 on t1(id2);
create index i_t2_id1 on t2(id1);
--//分析略.
2.测试:
SCOTT@test01p> alter session set statistics_level = all;
Session altered.
SCOTT@test01p> select * from t1 where t1.id1 in (select t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
ID1 ID2 NAME
---------- ---------- ----------------------------------------------------------------------------------------------------
10 10 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
11 11 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID gz5pqkg6svm7k, child number 0
-------------------------------------
select * from t1 where t1.id1 in (select t2.id1 from t2 where
t2.id1=11 ) or (t1.id2=10 )
Plan hash value: 1962644737
-------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 30 (100)| | 2 |00:00:00.01 | 115 |
|* 1 | FILTER | | 1 | | | | | 2 |00:00:00.01 | 115 |
| 2 | TABLE ACCESS FULL| T1 | 1 | 6000 | 638K| 30 (0)| 00:00:01 | 6000 |00:00:00.01 | 113 |
|* 3 | FILTER | | 5999 | | | | | 1 |00:00:00.01 | 2 |
|* 4 | INDEX RANGE SCAN| I_T2_ID1 | 1 | 1 | 4 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
-------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1 / T1@SEL$1
3 - SEL$2
4 - SEL$2 / T2@SEL$2
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("T1"."ID2"=10 OR IS NOT NULL))
3 - filter(11=:B1)
4 - access("T2"."ID1"=:B1)
32 rows selected.
--//执行计划存在1个全表扫描.里面的索引选择性很好,oracle并没有选择合理的执行计划.
--//而且有1个小小的细节,id=4的starts=1,而前面的id=3的starts=5999.你可以看出这里oracle显示执行计划有1个小小的bug.
--//id=4的starts应该是5999.这样看到的逻辑读不应该是后面的2而是2*5999 = 11998.
--//而且你可以看出oracle忽略的id=4多次INDEX RANGE SCAN的成本.
--//链接http://www.itpub.net/thread-2107240-2-1.html里面的显示倒是正确的.它的版本是11.2.0.4.180717.
3.是否通过提示优化sql语句:
--//首先想到的是USE_CONCAT.
select /*+ USE_CONCAT(@"SEL$1" 8 OR_PREDICATES(1)) */ * from t1 where t1.id1 in (select /*+unnest */ t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
--//执行计划如下:
-------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 33 (100)| | 2 |00:00:00.01 | 118 |
| 1 | CONCATENATION | | 1 | | | | | 2 |00:00:00.01 | 118 |
| 2 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 1 | 1 | 109 | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 3 | INDEX RANGE SCAN | I_T1_ID2 | 1 | 1 | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 4 | FILTER | | 1 | | | | | 1 |00:00:00.01 | 114 |
|* 5 | TABLE ACCESS FULL | T1 | 1 | 5999 | 638K| 30 (0)| 00:00:01 | 5999 |00:00:00.01 | 112 |
|* 6 | FILTER | | 5999 | | | | | 1 |00:00:00.01 | 2 |
|* 7 | INDEX RANGE SCAN | I_T2_ID1 | 1 | 1 | 4 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
-------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1_1 / T1@SEL$1
3 - SEL$1_1 / T1@SEL$1
5 - SEL$1_2 / T1@SEL$1_2
6 - SEL$2
7 - SEL$2 / T2@SEL$2
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("T1"."ID2"=10)
4 - filter( IS NOT NULL)
5 - filter(LNNVL("T1"."ID2"=10))
6 - filter(11=:B1)
7 - access("T2"."ID1"=:B1)
--//很奇怪id=4,依旧选择过滤,unnest提示没有用.实际上使用USE_CONCAT相当每个or分支加入LNNVL(条件)来排他符合条件的记录.
--//也就是oracle依旧选择的执行计划不是很理想,甚至比前面还要差.
4.尝试OR_EXPAND提示:
select /*+ OR_EXPAND */ * from t1 where t1.id1 in (select /*+ unnest */ t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
--//执行计划如下:
Plan hash value: 1716482303
----------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | | 5 (100)| | 2 |00:00:00.01 | 9 |
| 1 | VIEW | VW_ORE_BA8ECEFB | 1 | 2 | 156 | 5 (0)| 00:00:01 | 2 |00:00:00.01 | 9 |
| 2 | UNION-ALL | | 1 | | | | | 2 |00:00:00.01 | 9 |
| 3 | TABLE ACCESS BY INDEX ROWID BATCHED | T1 | 1 | 1 | 109 | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 4 |
|* 4 | INDEX RANGE SCAN | I_T1_ID2 | 1 | 1 | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
| 5 | NESTED LOOPS SEMI | | 1 | 1 | 113 | 3 (0)| 00:00:01 | 1 |00:00:00.01 | 5 |
|* 6 | TABLE ACCESS BY INDEX ROWID BATCHED| T1 | 1 | 1 | 109 | 2 (0)| 00:00:01 | 1 |00:00:00.01 | 3 |
|* 7 | INDEX RANGE SCAN | I_T1_ID1 | 1 | 1 | | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
|* 8 | INDEX RANGE SCAN | I_T2_ID1 | 1 | 1 | 4 | 1 (0)| 00:00:01 | 1 |00:00:00.01 | 2 |
----------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SET$9162BF3C / VW_ORE_BA8ECEFB@SEL$BA8ECEFB
2 - SET$9162BF3C
3 - SET$9162BF3C_1 / T1@SEL$1
4 - SET$9162BF3C_1 / T1@SEL$1
5 - SEL$C90BA1D5
6 - SEL$C90BA1D5 / T1@SEL$1
7 - SEL$C90BA1D5 / T1@SEL$1
8 - SEL$C90BA1D5 / T2@SEL$2
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('12.2.0.1')
DB_VERSION('12.2.0.1')
ALL_ROWS
OUTLINE_LEAF(@"SEL$C90BA1D5")
UNNEST(@"SEL$2")
OUTLINE_LEAF(@"SET$9162BF3C_1")
OUTLINE_LEAF(@"SET$9162BF3C")
OR_EXPAND(@"SEL$1" (1) (2))
OUTLINE_LEAF(@"SEL$BA8ECEFB")
OUTLINE(@"SET$9162BF3C_2")
OUTLINE(@"SEL$2")
OUTLINE(@"SET$9162BF3C")
OR_EXPAND(@"SEL$1" (1) (2))
OUTLINE(@"SEL$1")
NO_ACCESS(@"SEL$BA8ECEFB" "VW_ORE_BA8ECEFB"@"SEL$BA8ECEFB")
INDEX_RS_ASC(@"SET$9162BF3C_1" "T1"@"SEL$1" ("T1"."ID2"))
BATCH_TABLE_ACCESS_BY_ROWID(@"SET$9162BF3C_1" "T1"@"SEL$1")
INDEX_RS_ASC(@"SEL$C90BA1D5" "T1"@"SEL$1" ("T1"."ID1"))
BATCH_TABLE_ACCESS_BY_ROWID(@"SEL$C90BA1D5" "T1"@"SEL$1")
INDEX(@"SEL$C90BA1D5" "T2"@"SEL$2" ("T2"."ID1"))
LEADING(@"SEL$C90BA1D5" "T1"@"SEL$1" "T2"@"SEL$2")
USE_NL(@"SEL$C90BA1D5" "T2"@"SEL$2")
END_OUTLINE_DATA
*/
Predicate Information (identified by operation id):
---------------------------------------------------
4 - access("T1"."ID2"=10)
6 - filter(LNNVL("T1"."ID2"=10))
7 - access("T1"."ID1"=11)
8 - access("T2"."ID1"=11)
filter("T1"."ID1"="T2"."ID1")
--//12c下oracle选择正确的执行计划.可以发现id=2使用UNION-ALL,也就是oracle做了查询转换成union all的形式.
--//另外我曾经尝试将ounline date的提示信息加入到11g环境,执行计划依旧没有选择OR_EXPAND.
--//通过10053事件看看.
SCOTT@test01p> @ 10053x cg5kmfhgczjfd 0
PL/SQL procedure successfully completed.
ORE: after OR Expansion:******* UNPARSED QUERY IS *******
SELECT "VW_ORE_BA8ECEFB"."ITEM_1" "ID1","VW_ORE_BA8ECEFB"."ITEM_2" "ID2","VW_ORE_BA8ECEFB"."ITEM_3" "NAME" FROM ( (SELECT "T1"."ID1" "ITEM_1","T1"."ID2" "ITEM_2","T1"."NAME" "ITEM_3" FROM "SCOTT"."T1" "T1" WHERE "T1"."ID2"=10) UNION ALL (SELECT "T1"."ID1" "ITEM_1","T1"."ID2" "ITEM_2","T1"."NAME" "ITEM_3" FROM "SCOTT"."T1" "T1" WHERE "T1"."ID1"=ANY (SELECT /*+ UNNEST */ "T2"."ID1" "ID1" FROM "SCOTT"."T2" "T2" WHERE "T2"."ID1"=11) AND LNNVL("T1"."ID2"=10))) "VW_ORE_BA8ECEFB"
--//格式化显示如下:
SELECT "VW_ORE_BA8ECEFB"."ITEM_1" "ID1"
,"VW_ORE_BA8ECEFB"."ITEM_2" "ID2"
,"VW_ORE_BA8ECEFB"."ITEM_3" "NAME"
FROM ( (SELECT "T1"."ID1" "ITEM_1"
,"T1"."ID2" "ITEM_2"
,"T1"."NAME" "ITEM_3"
FROM "SCOTT"."T1" "T1"
WHERE "T1"."ID2" = 10)
UNION ALL
(SELECT "T1"."ID1" "ITEM_1"
,"T1"."ID2" "ITEM_2"
,"T1"."NAME" "ITEM_3"
FROM "SCOTT"."T1" "T1"
WHERE "T1"."ID1" = ANY (SELECT /*+ UNNEST */
"T2"."ID1" "ID1"
FROM "SCOTT"."T2" "T2"
WHERE "T2"."ID1" = 11)
AND LNNVL ("T1"."ID2" = 10))) "VW_ORE_BA8ECEFB";
--//也就是oracle查询转换为 UNION ALL的形式.
--//你可以看到第2个条件人为的加入LNNVL ("T1"."ID2" = 10).
--// OR_EXPAND 提示 与 USE_CONCAT 提示到底有什么不同?
5.补充使用USE_CONCAT看到的情况:
select /*+ USE_CONCAT(@"SEL$1" 8 OR_PREDICATES(1)) */ * from t1 where t1.id1 in (select /*+unnest */ t2.id1 from t2 where t2.id1=11 ) or (t1.id2=10 );
SCOTT@test01p> @ 10053x 18h6hkqcqq3w2 0
PL/SQL procedure successfully completed.
--//看这些太烦,不过可以发现如下:
LORE: Or-Expansion validity checks failed on query block SEL$2 (#2) because Cost based OR expansion enabled
SYS@test01p> @ hide or_exp
old 10: and lower(a.ksppinm) like lower('%&1%')
new 10: and lower(a.ksppinm) like lower('%or_exp%')
NAME DESCRIPTION DEFAULT_VALUE SESSION_VALUE SYSTEM_VALUE
---------------------------------- ------------------------------------------------- ------------- ------------- ------------
_no_or_expansion OR expansion during optimization disabled TRUE FALSE FALSE
_optimizer_cbqt_or_expansion enables cost based OR expansion TRUE ON ON
_optimizer_interleave_or_expansion interleave OR Expansion during CBQT TRUE TRUE TRUE
_optimizer_or_expansion control or expansion approach used TRUE DEPTH DEPTH
_optimizer_or_expansion_subheap Use subheap for optimizer or-expansion TRUE TRUE TRUE
_or_expand_nvl_predicate enable OR expanded plan for NVL/DECODE predicate TRUE TRUE TRUE
6 rows selected.
--//也就是12c缺省打开因为以上原因.不过我尝试"_optimizer_cbqt_or_expansion"=off也无效.放弃!!
--//我也尝试提高全表扫描的成本看看是否执行计划会发生改变,不过依旧没用.
SCOTT@test01p> exec dbms_stats.SET_TABLE_STATS(user,'T1',NUMBLKS=>800000000000);
PL/SQL procedure successfully completed.
[20181220]使用提示OR_EXPAND优化.txt的更多相关文章
- [20190524]使用use_concat or_expand提示优化.txt
[20190524]使用use_concat or_expand提示优化.txt --//上午看了链接https://connor-mcdonald.com/2019/05/22/being-gene ...
- [20181116]18c DML 日志优化.txt
[20181116]18c DML 日志优化.txt 1.环境:xxxxxxxx> select banner_full from v$version;BANNER_FULL---------- ...
- [20200223]关于latch and mutext的优化.txt
[20200223]关于latch and mutext的优化.txt --//前一段时间一直在测试使用DBMS_SHARED_POOL.MARKHOT标识热对象以及sql语句的优化.--//有别人问 ...
- solr入门之參考淘宝搜索提示功能优化拼音加汉字搜索功能
首先看一下从淘宝输入搜索keyword获取到的一些数据信息: 第一张:使用拼音的全程来查询 能够看到提示的是匹配的转换的拼音的方式,看最后一个提示项 这里另一个在指定分类文件夹下搜索的功能,难道后台还 ...
- dense_rank()+hash提示改写优化SQL
数据库环境:SQL SERVER 2005 今天看到一条SQL,返回10条数据,执行了50多S.刚好有空,就对它进行了优化,优化后1S出结果. 先看下原始SQL SELECT t1.line_no , ...
- nginx-502错误,老是提示busy.优化php-fpm如下
[global]pid = /usr/local/php/var/run/php-fpm.piderror_log = /usr/local/php/var/log/php-fpm.loglog_le ...
- 一百零三:CMS系统之使用sweetalert提示框优化返回结果
在base模板中引用 在修改密码的js中使用 $(function () { $('#submit').click(function (evnet) { evnet.preventDefault(); ...
- sql 优化 链接提示 查询提示 标提示
SQL Server的查询优化器在select查询执行的时候产生一个高效的查询执行计划.如果优化器不能选择最优的计划,那么就需要检查查询计划.统计信息.支持的索引等,而通过使用提示可以改变优化器选择查 ...
- MySQL优化篇(一),我可以和面试官多聊几句吗?——SQL优化流程与优化数据库对象
我可以和面试官多聊几句吗?只是想偷点技能过来.MySQL优化篇(基于MySQL8.0测试验证),上部分:优化SQL语句.数据库对象,MyISAM表锁和InnoDB锁问题. MyISAM表锁和InnoD ...
随机推荐
- SpringCloud入门之Spring Boot多环境配置切换指南
在 spring boot 中,有两种配置文件,一种是application.properties,另一种是application.yml,两种都可以配置spring boot 项目中的一些变量的定义 ...
- 深入理解Java虚拟机阅读心得(一)
JVM(Java Virtual Machine) 即Java虚拟机,是一种用于计算设备的规范,用于运行Java程序编译后得到的字节码文件(Class文件) 一.JVM的内存区域 1.程序计数器(Pr ...
- html中的Session
采用setItem()方法存储 sessionStorage.setItem('testKey','这是一个测试的value值'); // 存入一个值sessionStorage.getItem('t ...
- MyBatis学习总结(四)——MyBatis缓存与代码生成
一.MyBatis缓存 缓存可以提高系统性能,可以加快访问速度,减轻服务器压力,带来更好的用户体验.缓存用空间换时间,好的缓存是缓存命中率高的且数据量小的.缓存是一种非常重要的技术. 1.0.再次封装 ...
- Tomcat日志设定
1 Tomcat 日志概述 Tomcat 日志信息分 为 两 类 : 一.是运行中的日志,它主要 记录 运行的一些信息,尤其是一些异常 错误 日志信息 .二.是 访问 日志信息,它 记录 的 访 ...
- 使用PoolingHttpClientConnectionManager解决友盟(umeng)推送在多线程环境推送失败的问题
在友盟(umeng)提供的服务端推送的sdk中,使用的是apache提供的httpclient.在单线程化境下,httpclient工作没有问题.但是由于umeng的sdk中并未考虑并发的情况,因此很 ...
- 线程 线程池 Task
首先声明 这是读了 愉悦的绅士 文章 <菜鸟之旅——学习线程(线程和线程池)> <Task与线程> 的一些个人总结,还是那句话,如有不对,欢迎指正 文章以代码加注释的方法展示. ...
- 解决org.hibernate.exception.SQLGrammarException:could not insert
今天在使用hibernate搭建项目时碰到了这个错误,找了好半天没能发现错误的原因, 上网求助了一下 发现出现这个bug的原因是因为数据表使用了数据库的关键字(保留字) 然后检查了一下,发现字段名称都 ...
- 【Java每日一题】20170309
20170308问题解析请点击今日问题下方的“[Java每日一题]20170309”查看(问题解析在公众号首发,公众号ID:weknow619) package Mar2017; public cla ...
- Netty实战十二之WebSocket
如果你有跟进Web技术的最新进展,你很可能就遇到过“实时Web”这个短语,这里并不是指所谓的硬实时服务质量(QoS),硬实时服务质量是保证计算结果将在指定的时间间隔内被递交.仅HTTP的请求/响应模式 ...