暂无图片
regexp_substr和substr函数在11g和19c的表现问题
我来答
分享
橘子熟了吗
2022-08-26
regexp_substr和substr函数在11g和19c的表现问题

哪位大佬帮忙协助分析一下regexp_substr和substr函数在11g和19c的表现问题:

DROP TABLE dba_man.REG_TEST;
DROP TABLE dba_man.REG_TEST2;
create table dba_man.reg_test(x int,y varchar2(20));
insert into dba_man.reg_test values (1,'1a2a3a4a');
insert into dba_man.reg_test values (2,'5a6a7a8a');
insert into dba_man.reg_test values (3,'9a10a11a12a');
insert into dba_man.reg_test values (4,'13a14a15a16a');
insert into dba_man.reg_test values (5,'17a18a19a20a');
alter table dba_man.reg_test add primary key (x);

create table dba_man.reg_test2(y varchar2(20));
insert into dba_man.reg_test2 values ('1');
insert into dba_man.reg_test2 values ('2');
insert into dba_man.reg_test2 values ('3');
insert into dba_man.reg_test2 values ('4');
insert into dba_man.reg_test2 values ('5');
insert into dba_man.reg_test2 values ('6');
insert into dba_man.reg_test2 values ('7');
insert into dba_man.reg_test2 values ('8');
insert into dba_man.reg_test2 values ('9');
insert into dba_man.reg_test2 values ('10');
insert into dba_man.reg_test2 values ('11');
insert into dba_man.reg_test2 values ('12');
insert into dba_man.reg_test2 values ('13');
insert into dba_man.reg_test2 values ('14');
insert into dba_man.reg_test2 values ('15');
insert into dba_man.reg_test2 values ('16');
insert into dba_man.reg_test2 values ('17');
insert into dba_man.reg_test2 values ('18');
insert into dba_man.reg_test2 values ('19');
insert into dba_man.reg_test2 values ('20');
alter table dba_man.reg_test2 add primary key (y);

test sql:

alter session set "_optimizer_mjc_enabled"=false;

select * from dba_man.reg_test where regexp_substr(y,'[0-9]+',1,rownum) in (select y from dba_man.reg_test2);

select substr(y,1,rownum),t1.* from dba_man.reg_test t1 where substr(y,1,rownum) in (select y from dba_man.reg_test2 T2);

11g:

| 4 | TABLE ACCESS FULL| REG_TEST | 5 | 125 | 3 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN| SYS_C0088536 | 20 | 240 | 0 (0)| 00:00:01 |  

19c:

| 4 | TABLE ACCESS FULL| REG_TEST | 5 | 125 | 3 (0)| 00:00:01 |

| 5 | INDEX FULL SCAN | SYS_C0017807 | 20 | 240 | 1 (0)| 00:00:01 | 

问题一:

11g中:
regexp_substr和substr中含rownum时,索引走INDEX UNIQUE SCAN;
19c中:
regexp_substr和substr中含rownum时,索引走INDEX FULL SCAN ;

问题2:
substr中含rownum时,11g和19c出来的结果集不一致。11g的出来2条,感觉是对的;19c的出来5条,感觉是错的。

11g执行结果:

 select substr(y,1,rownum),t1.* from dba_man.reg_test t1 where substr(y,1,rownum) in (select y from dba_man.reg_test2 T2);

SUBSTR(Y,1,ROWNUM) X Y
-------------------------------------------------------------------------------- ---------- --------------------
1 1 1a2a3a4a
13 4


19c执行结果:

select substr(y,1,rownum),t1.* from dba_man.reg_test t1 where substr(y,1,rownum) in (select y from dba_man.reg_test2 T2);

SUBSTR(Y,1,ROWNUM) X Y
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ---------- ------------------------------------------------------------
1 1 1a2a3a4a
13 4 13a14a15a16a
17a 5 17a18a19a20a
5a6a 2 5a6a7a8a

9a10a 3 9a10a11a12a 

我来答
添加附件
收藏
分享
问题补充
2条回答
默认
最新
橘子熟了吗
升级问题到: 潜在风险
暂无图片 评论
暂无图片 有用 0
打赏 0
DarkAthena

对于问题2:
19c的这条sql

select /*+ OPT_PARAM('_optimizer_mjc_enabled','false') */ substr(y, 1, rownum), t1.* from reg_test t1 where substr(t1.y, 1, rownum) in (select t2.y from reg_test2 T2);
复制

其实是按下面这个样子执行的

select /*+ OPT_PARAM('_optimizer_mjc_enabled','false') */ substr(y, 1, rownum), t1.* from reg_test t1 where substr(t1.y, 1, (select rownum from dual)) in (select t2.y from reg_test2 T2);
复制

也就是说,条件中函数的参数里如果有rownum,rownum就等于1

你可以尝试删掉一行记录再测试查询,来验证我的说法

delete reg_test2 where y='9';
复制

这个问题其实和我这个月写的一篇文章有相似之处,就是rownum在某些时候会直接认为是等于1,而不是查询数据的行数。

当rownum被函数嵌套作为查询条件时,存在一个矛盾点,就是rownum永远是在数据查询出来后,才知道有多少行,才能得到rownum列的值,这和where条件中的函数执行起了冲突,因为得到rownum的值后,传入函数,可能又不满足条件了,因此11g的处理行为是存在歧义的,相较而言,19c处理的结果则不存在歧义。

另外,不用_optimizer_mjc_enabled=false,你会发现11g里查出来只有1行了,数据行数变了;而19c不管加不加_optimizer_mjc_enabled=false,查询出来的数据条目数都不会变化。

在某些情况下hint或者参数的调整并不一定会生效,无论使用什么执行计划,查询出来的结果应该都要一致。因此,11g改个hint就导致数据查询结果都不同,可以理解为是BUG了

暂无图片 评论
暂无图片 有用 0
打赏 0
回答交流
Markdown


请输入正文
提交
相关推荐
OGG同步表对象trigger跟job问题
回答 3
是的,需要禁掉目标表的触发器、级联删除、约束和Job
RAC 启动后两节点无法互相识别
回答 9
暂无文字回复
Oracle:用pl/sql导入,总是死机,这是什么原因?
回答 2
已采纳
如果是用plsqldeveloper以复制粘贴的方式导入大量数据的话,界面可能会出现无响应,但这并不是死机,后台还是在运行的。另外,还要检查下是不是已经产生锁表的情况了
Oracle测试
回答 1
第一个可以使用pl/sql循环插入来完成,不过2亿条还有blob字段,会很慢,需要的空间也会很大。第二个这个用简单的shell脚本或者Python就可以实现的
已经搭建ADG的库,若主从同时调整在线日志的大小,比如2G到8G,对从库的同步会有影响么?
回答 4
已采纳
对应的standbylog也要做相应的调整。如果不调整可能的影响就是会有延迟吧。
新来了一位dba,把数据搞挂了,让我背锅,怎么办!
回答 4
已采纳
忍者吧,下次继续背锅;然后成为名副其实的背锅侠。
大佬能不能帮我写一个imp的脚本
回答 7
使用如下命令看是否连接的上sqlplussystem/密码@IP地址:1521/sid
查询最近一个月都有哪些Oracle用户登录,怎么查询?
回答 1
已采纳
可以看下dbahistactivesessionhistory,但是只能每10分钟采样一次。
ORACLE执行计划里,最后一列的时间到底怎么看
回答 3
已采纳
最后一列的TIME,是他所有子节点时间的累加值,5不是2的子节点。
Oracle roll invalidation的超时时长怎么查看?
回答 1
已采纳
下面隐含参数可以一定程度控制,11g版本以后,下面参数只是一个基准值,会在下面参数基础上有一定浮动。optimizerinvalidationperiod18000TRUEtimewindowfori