暂无图片
oracle中char关联问题
我来答
分享
杨豹
2025-02-18
oracle中char关联问题
暂无图片 5M
create table t1(id int, name char(10));
create table t2(id int, name char(12));
insert into t1 values(100, 'yang');
insert into t2 values(200, 'yang');
commit;

select * from t1, t2 where t1.name = t2.name and t1.name = 'yang'; -- return 1 row

select * from t1, t2 where t1.name = t2.name and t1.name = rpad('yang', 10); -- return 1 row

with tmp as ( select id, name from t2 where name = rpad('yang', 12) )
select * from t1, tmp where t1.name = tmp.name and t1.name = 'yang'; -- return 1 row

with tmp as ( select id, name from t2 where name = rpad('yang', 12) )
select * from t1, tmp where t1.name = tmp.name and t1.name = rpad('yang', 10); -- return 0 row
复制

为什么最后一个查询没有结果

我来答
添加附件
收藏
分享
问题补充
1条回答
默认
最新
DarkAthena
  1. 第一条SQL,等号两侧都是char类型,char类型的比较是把短的值的右侧补空格补到和长侧的长度一致后再比,因此能查出来。
  2. 在ORACLE中,rpad('yang', 10)varchar2(10)类型,当它和char(10)进行比较时,其实是跨类型比较,char会保留原本的空格,隐式转换成varchar2类型再进行比较,所以第2条查询SQL能查到记录。
  3. 对于第4条,条件 name = rpad('yang', 12)t1.name = tmp.name and t1.name = rpad('yang', 10) 在ORACLE里会自动优化成name = rpad('yang', 12) and name = rpad('yang', 10)
    t1.name = rpad('yang', 10) and t1.name = rpad('yang', 12);,此时条件不满足,返回0行

下面是最后一条SQL的执行计划,可以数数空格

<report db_version="11.2.0.4.0">
  <report_id><![CDATA[/orarep/xplan/typical?table=PLAN_TABLE&type=TYPICAL]]></report_id>
  <plan>
    <operation name="SELECT STATEMENT" id="0" depth="0" pos="0">
      <card>1</card>
      <bytes>39</bytes>
      <cost>0</cost>
      <io_cost>0</io_cost>
      <cpu_cost>0</cpu_cost>
    </operation>
    <operation name="FILTER" id="1" depth="1" pos="1">
      <project>&quot;T1&quot;.&quot;ID&quot;[NUMBER,22]</project>
      <predicates type="filter">NULL IS NOT NULL</predicates>
      <qblock>SEL$58A6D7F6</qblock>
      <other_xml>
        <info type="db_version">11.2.0.4</info>
        <info type="parse_schema"><![CDATA["SYSTEM"]]></info>
        <info type="dynamic_sampling">2</info>
        <info type="plan_hash">487071653</info>
        <info type="plan_hash_2">2304446132</info>
        <outline_data>
          <hint><![CDATA[USE_HASH(@"SEL$58A6D7F6" "T2"@"SEL$1")]]></hint>
          <hint><![CDATA[LEADING(@"SEL$58A6D7F6" "T1"@"SEL$2" "T2"@"SEL$1")]]></hint>
          <hint><![CDATA[FULL(@"SEL$58A6D7F6" "T2"@"SEL$1")]]></hint>
          <hint><![CDATA[FULL(@"SEL$58A6D7F6" "T1"@"SEL$2")]]></hint>
          <hint><![CDATA[OUTLINE(@"SEL$1")]]></hint>
          <hint><![CDATA[OUTLINE(@"SEL$2")]]></hint>
          <hint><![CDATA[MERGE(@"SEL$1")]]></hint>
          <hint><![CDATA[OUTLINE_LEAF(@"SEL$58A6D7F6")]]></hint>
          <hint><![CDATA[ALL_ROWS]]></hint>
          <hint><![CDATA[DB_VERSION('11.2.0.4')]]></hint>
          <hint><![CDATA[OPTIMIZER_FEATURES_ENABLE('11.2.0.4')]]></hint>
          <hint><![CDATA[IGNORE_OPTIM_EMBEDDED_HINTS]]></hint>
        </outline_data>
      </other_xml>
    </operation>
    <operation name="HASH JOIN" id="2" depth="2" pos="1">
      <card>1</card>
      <bytes>39</bytes>
      <cost>4</cost>
      <io_cost>4</io_cost>
      <cpu_cost>615433</cpu_cost>
      <time>00:00:01 </time>
      <project>(#keys=1) &quot;T1&quot;.&quot;ID&quot;[NUMBER,22]</project>
      <predicates type="access">&quot;T1&quot;.&quot;NAME&quot;=&quot;NAME&quot;</predicates>
    </operation>
    <operation name="TABLE ACCESS" options="FULL" id="3" depth="3" pos="1">
      <object>T1</object>
      <card>1</card>
      <bytes>25</bytes>
      <cost>2</cost>
      <io_cost>2</io_cost>
      <cpu_cost>7591</cpu_cost>
      <time>00:00:01 </time>
      <project>&quot;T1&quot;.&quot;ID&quot;[NUMBER,22], &quot;T1&quot;.&quot;NAME&quot;[CHARACTER,10]</project>
      <predicates type="filter">&quot;T1&quot;.&quot;NAME&quot;=&apos;yang      &apos; AND &quot;T1&quot;.&quot;NAME&quot;=&apos;yang        &apos;</predicates>
      <qblock>SEL$58A6D7F6</qblock>
      <object_alias>T1@SEL$2</object_alias>
    </operation>
    <operation name="TABLE ACCESS" options="FULL" id="4" depth="3" pos="2">
      <object>T2</object>
      <card>1</card>
      <bytes>14</bytes>
      <cost>2</cost>
      <io_cost>2</io_cost>
      <cpu_cost>7591</cpu_cost>
      <time>00:00:01 </time>
      <project>&quot;NAME&quot;[CHARACTER,12]</project>
      <predicates type="filter">&quot;NAME&quot;=&apos;yang        &apos; AND &quot;NAME&quot;=&apos;yang      &apos;</predicates>
      <qblock>SEL$58A6D7F6</qblock>
      <object_alias>T2@SEL$1</object_alias>
    </operation>
  </plan>
</report>
复制

或者把这个SQL换个形式表达,就是这样:

select *
  from t1, t2 
 where t1.name = t2.name
   and t1.name = rpad('yang', 10)
   and t2.name = rpad('yang', 12);
复制

很明显 rpad('yang', 10)是不等于rpad('yang', 12) 的,所以条件恒为假

另外,其实这里还有个问题,rpad函数在入参为常量时,会提前优化掉,但是如果写个自定义函数调用内置的rpad,然后把sql里的函数换成自定义的rpad,由于未执行优化,所以数据能查出来

drop table t1; drop table t2; create table t1(id int, name char(4)); create table t2(id int, name char(5)); insert into t1 values(100, 'wang'); insert into t2 values(200, 'wang'); commit; create or replace function rpad5(str varchar2,len number,pad varchar2 default ' ') return varchar2 is begin return rpad(str,len,pad); end; / select * from t1, t2 where t1.name = t2.name and t1.name = rpad5('wang' ,4,' ') and t2.name = rpad5('wang' ,5,' ') ;--return 1 row select * from t1, t2 where t1.name = t2.name and t1.name = rpad('wang' ,4,' ') and t2.name = rpad('wang' ,5,' ') ;--return 0 row
复制

ORACLE的char类型有很多特殊处理,一旦叠加上SQL优化器的一些自动处理,会出现很多反直觉的场景

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


请输入正文
提交
相关推荐
Oracle 建表的时候没有创建子分区, 如果想增加只能重新创建表吗?
回答 1
已采纳
12c开始可以直接modify
大佬们,等保有个整改需求,能帮我看看怎么改吗
回答 5
先明确等保的要求吧,是要求操作系统下的,还是数据库层面的。无非就是按照需求建用户授权。
硬解析会对数据库性能产生哪些影响?
回答 1
已采纳
‌1、增加CPU和内存资源的使用‌:硬解析过程中需要生成执行计划,这需要消耗大量的CPU资源和SGA中的内存资源。此外,硬解析过程中需要申请和使用闩,而在资源有限的情况下,大量的闩使用会导致进程等待,
Oracle expdp可以把文件指向asm里吗?
回答 1
已采纳
可以,创建导出目录在asm里即可;CREATE&nbsp;DIRECTORYASMDIRDUMPas'DISKGROUP1/';
oracle 12C集群,补丁回退之后,有文件权限不对
回答 6
Scripttocaptureandrestorefilepermissioninadirectory(foreg.ORACLEHOME)(文档ID1515018.1)
oracle 双节点rac 11g 安装软件时报错 CRS-2613 CRS-4000
回答 1
主要问题是ASM实力没有运行正常,和oc4j关系不大
linxu8安装oracle无法调用图形化?
回答 3
已采纳
先想办法把时钟能调出来,然后再排查访问工具设置。祝你成功!
oracle12C RAC共享磁盘设置
回答 1
盘的大小最好都一样,也可以创建不同的磁盘组,比如把f、k放到一个磁盘组,e、j放一个磁盘组,c、h;dbji放一个磁盘组另外还有留3个小盘放OCR。
oracle 生产库的内存管理是自动还是手动管理?
回答 1
已采纳
可以设置成自动管理。不过个别场景下会出现一些波动。资深的一些专家不建议,他们说Oracle的自动在OLAP上厉害,OLTP上还要提升。不过一般的场景问题不大。你要是不放心SGA和PGA还是自己设定也行
RAC停止数据库
回答 2
已采纳
srvctlstopinstance命令是通过集群进程来停止实例,它会在整个RAC集群中发送停止实例的命令,shutdownimmediate命令只会停止当前节点上的实例。srvctlstopinst