从Java的类型转换看MySQL和Oracle中的隐式转换

说起数据类型转换,在开发中如此,在数据库中也是如此,之前简单对比过MySQL和Oracle的数据类型转换情况,可以参见MySQL和Oracle中的隐式转换
不过当时写完之后,有个读者随口问了一句为什么,为什么呢?似乎自己还是一知半解,说是规则,无规矩不成方圆,倒也无可非议,不过我觉得还是要再看看,看看还能有哪些收获,接下来的内容我就不能保证正确性了,希望大家明辨,也希望提出意见,毕竟就是希望把问题搞明白而已。

首先开发语言中就有数据类型的隐式转换,这一点在java中尤为明显,毕竟一个承载了太多使命的语言如此庞大,又是强类型语言,数据类型的转换就是一个尤为重要的部分了。Java中的数据类型转换主要有下面的规则。
//转换规则:从存储范围小的类型到存储范围大的类型。
//具体规则为:byte→short(char)→int→long→float→double
自己也嘚瑟了一下,写了个简单的小程序以示明证,这个程序不能说明我会java.
 public class Test {
 public static void main(String args[]){
 /*1*/    System.out.println("aa");
/*2*/    System.out.println('a');
/*3*/    byte a=10;
/*4*/    System.out.println(a);
/*5*/    char b='b';
/*6*/    int c=b;
/*7*/    System.out.println(b);
/*8*/    System.out.println(c);
    }
 }
这个程序的输出为
aa
 a
 10
 b
 98

这样写的目的就是,
 第1行,第2行中的单引号,双引号需要做的事情就是标示它是一个变量值,两者的效果在这个时候是一致的。
 第3行初始化了一个byte变量,然后输出,这个时候还是byte
但是第5行声明了一个char型变量,然后在第6行中做了类型的隐式转换,在第7行中输出为字符b,但是在第8行输出为
 通过这个简单的例子可以发现确实数据类型做了隐式转换,而且单引号,双引号在这个例子中的作用是一致的,就是标示变量。
 因为在Java中查看数据类型的转换代价还是相对要困难一些,我们可以在数据库中来类比。
 首先还是重复之前的测试,准备一批的数据。创建一个表,然后插入一些值。
create table test (id1 number,id2 varchar2(10));
  begin                 
    for i in 1..100 loop
    insert into test values(i,chr(39)||i||chr(39));
    end loop;
    commit;
    end;
    /
 create index ind1_test on n1.test(id1);
 create index ind2_test on n1.test(id2);
然后收集统计信息。
exec dbms_stats.gather_table_stats('TEST','TEST',CASCADE=>TRUE);
这个时候查看执行计划
explain plan for select *from test where id1='2';
 SQL>  select *from table(dbms_xplan.display);
 PLAN_TABLE_OUTPUT
 ----------------------------------------------------------------------------------------------------
 Plan hash value: 2759464289
 -----------------------------------------------------------------------------------------
 | Id  | Operation                  | Name      | Rows  | Bytes | Cost (%CPU)| Time    |
 -----------------------------------------------------------------------------------------
 |  0 | SELECT STATEMENT            |          |    1 |    20 |    1  (0)| 00:00:01 |
 |  1 |  TABLE ACCESS BY INDEX ROWID| TEST      |    1 |    20 |    1  (0)| 00:00:01 |
 |*  2 |  INDEX RANGE SCAN          | IND1_TEST |    1 |      |    1  (0)| 00:00:01 |
 -----------------------------------------------------------------------------------------
 Predicate Information (identified by operation id):
 PLAN_TABLE_OUTPUT
 -------------------------------------------------------------
    2 - access("ID1"=2)
通过这个确实可以看到谓词信息的部分    2 - access("ID1"=2) 已经自动做了转换,这个时候一个触发了一个索引扫描。
 但是这个过程还是看不出有数据类型转换的痕迹,我们做一个看似有问题的例子,来触发一下。尽管id1位int型,但是使用字符型来触发。
SQL>    explain plan for select *from test where id1='A';
 Explained.
 SQL>  select *from table(dbms_xplan.display);
 PLAN_TABLE_OUTPUT
 ----------------------------------------------------------------------------------------------------
 Plan hash value: 2759464289
 -----------------------------------------------------------------------------------------
 | Id  | Operation                  | Name      | Rows  | Bytes | Cost (%CPU)| Time    |
 -----------------------------------------------------------------------------------------
 |  0 | SELECT STATEMENT            |          |    1 |    20 |    1  (0)| 00:00:01 |
 |  1 |  TABLE ACCESS BY INDEX ROWID| TEST      |    1 |    20 |    1  (0)| 00:00:01 |
 |*  2 |  INDEX RANGE SCAN          | IND1_TEST |    1 |      |    1  (0)| 00:00:01 |
 -----------------------------------------------------------------------------------------
 Predicate Information (identified by operation id):
 PLAN_TABLE_OUTPUT
 ------------------------------------------------
    2 - access("ID1"=TO_NUMBER('A'))
可以看到谓词信息已经发生了变化。  2 - access("ID1"=TO_NUMBER('A'))从这个地方我们可以看到确实触发了一个to_number的操作。
 而优化器在这个时候虽然触发了,但是在sql运行的时候,就会报出错误,这个时候可以看到Oracle还是蛮严谨的。
SQL> select *from test where id1='A';
 select *from test where id1='A'
                            *
 ERROR at line 1:
 ORA-01722: invalid number
而如果使用双引号,生成执行计划都会抛错。
SQL> explain plan for select *from test where id1="A";
explain plan for select *from test where id1="A"
                                            *
ERROR at line 1:
ORA-00904: "A": invalid identifier
可见单引号和双引号在Oracle代表的含义还是有很大差别。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0addcd226efa1531a5f1852b99ecafd2.html