[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 ...
随机推荐
- two's complement,2的补码
本文为作者原创,允许转载,但必须注明原文地址:https://www.cnblogs.com/byronxie/p/10117265.html Let's start with one questio ...
- 【EF6学习笔记】(十二)EF高级应用场景
本篇原文链接:Advanced Entity Framework Scenarios 本篇主要讲一些使用Code First建立ASP.NET WEB应用的时候除了基础的方式以外的一些扩展方式方法: ...
- SharePoint如何配置Ipad跳转等问题
如何配置Ipad跳转 Apple iPad 设备上不支持 SharePoint 标准视图.用户可以改用移动视图在 iPad 设备上查看 SharePoint 内容.默认情况下,iPad 用户被重定向到 ...
- MyBatis源码解析(八)——Type类型模块之TypeAliasRegistry(类型别名注册器)
原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6705769.html 1.回顾 前面几篇讲了数据源模块,这和之前的事务模块都是enviro ...
- springMVC中的注解@RequestParam与@PathVariable的区别
1.@PathVariable @PathVariable绑定URI模板变量值 @PathVariable是用来获得请求url中的动态参数的 @PathVariable用于将请求URL中的模板变量映射 ...
- IdentityServer4 中文文档 -15- (快速入门)添加 JavaScript 客户端
IdentityServer4 中文文档 -15- (快速入门)添加 JavaScript 客户端 原文:http://docs.identityserver.io/en/release/quicks ...
- 使用.Net Core 2.1开发Captcha图片验证码服务
更新后续篇:Captcha服务(后续1) 使用.Net Core 2.1开发Captcha验证码服务 开发工具:Visual Studio 2017 15.7.3 开发平台:64位 Windows 1 ...
- ASP.NET WEB API简介
ASP.NET WEB API是基于.NET Framework用来构建Restful软件架构的框架,它是基于HTTP协议.Http不只是能够生成我们常见的web页面,它更是能够建立服务和面向资源 ...
- [android] 线性布局和布局的组合
/****************2016年4月25日 更新******************************/ 知乎:对于开发者来说,Android 的开发者选项里有哪些实用的功能? 汤涛 ...
- C++中的stack类、QT中的QStack类
C++中的stack 实现一种先进后出的数据结构,是一个模板类. 头文件 #include<stack> 用法(以int型为例): stack <int> s; //定义一个i ...