专栏首页杨建荣的学习笔记从Java的类型转换看MySQL和Oracle中的隐式转换(二)(r6笔记第68天)

从Java的类型转换看MySQL和Oracle中的隐式转换(二)(r6笔记第68天)

说起数据类型转换,在开发中如此,在数据库中也是如此,之前简单对比过MySQL和Oracle的数据类型转换情况,可以参见MySQL和Oracle中的隐式转换 http://blog.itpub.net/23718752/viewspace-1787973/ 不过当时写完之后,有个读者随口问了一句为什么,为什么呢?似乎自己还是一知半解,说是规则,无规矩不成方圆,倒也无可非议,不过我觉得还是要再看看,看看还能有哪些收获,接下来的内容我就不能保证正确性了,希望大家明辨,也希望提出意见,毕竟就是希望把问题搞明白而已。 首先开发语言中就有数据类型的隐式转换,这一点在java中尤为明显,毕竟一个承载了太多使命的语言如此庞大,又是强类型语言,数据类型的转换就是一个尤为重要的部分了。Java中的数据类型转换主要有下面的规则。 //转换规则:从存储范围小的类型到存储范围大的类型。 //具体规则为:byte→short(char)→int→long→float→double 自己也嘚瑟了一下,写了个简单的小程序以示明证,这个程序不能说明我会java.

public class Test {
public static void main(String args[]){
    System.out.println("aa");
    System.out.println('a');
    byte a=10;
     System.out.println(a);
     char b='b';
     int c=b;
     System.out.println(b);
     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代表的含义还是有很大差别。 我们来看看在MySQL中的表现。 还是创建一个简单的表,插入一些数据。 > create table test (id1 int,id2 varchar(10)); > insert into test values(1,'1'); > insert into test values(2,'2'); > insert into test values(3,'3'); > commit; > create index idx_id1 on test(id1); > create index idx_id2 on test(id2); 这个时候生成执行计划,可以发现走了索引

> explain select * from test where id1='1';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | test  | ref  | idx_id1       | idx_id1 | 5       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)

而如果查看id1为varchar的类型时,也走了索引。

> explain select * from test where id1='a';
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | test  | ref  | idx_id1       | idx_id1 | 5       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)

差别更大的就是如果使用id1='a',也能够正常执行,只是没有任何匹配的记录。 > select * from test where id1='a'; Empty set (0.00 sec) 而如果由单引号改为双引号,也能够正常运行。 > select * from test where id1="a"; Empty set (0.00 sec) 而且双引号的情况下,生成执行计划也没有问题。

> explain select * from test where id1="a";
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key     | key_len | ref   | rows | Extra       |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
|  1 | SIMPLE      | test  | ref  | idx_id1       | idx_id1 | 5       | const |    1 | Using where |
+----+-------------+-------+------+---------------+---------+---------+-------+------+-------------+
1 row in set (0.00 sec)

可以看出在MySQL中这个时候的范围似乎更宽,在MySQL中不光用单引号,双引号,而且还经常会看到·这种符号。 这种在MySQL中可以灵活声明一些变化个,举个不太恰当的例子,比如我们创建一个表,一个字段为int,类型为int直接按照下面的方式来写,肯定抛错。 > create table test1(int int); ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'int int)' at line 1 crea' at line 1 可以加上·,就可以识别了。 > create table test1(`int` int); Query OK, 0 rows affected (0.00 sec)

这个对比的跨度有点大,但是通过一些小把戏似乎还是能够看出在这些类型的转换中,优化器这边的触发情况。再接再厉,继续探究。

本文分享自微信公众号 - 杨建荣的学习笔记(jianrong-notes),作者:杨建荣

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2015-09-24

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 物化视图刷新的问题及分析(61天)

    最近现场需要搭建一套全新的环境,对于数据字典的管理采用了物化视图,因为数据量不大,采用了全量刷新的方式。因为有好几套环境,有几套环境是通过db link和主节点...

    jeanron100
  • Oracle和MySQL竟然可以这么写这样的SQL?(r12笔记第99天)

    今天看到Franck Pachot‏ 发了一个Twitter,意思是Oracle里的SQL还能这么写。猛一看确实让人有些意外。 ? 禁不住诱惑,自己也尝试了一番...

    jeanron100
  • 同样的sql执行结果不同的原因分析 (r4笔记第27天)

    今天开发的同事问我一个问题,说有一个sql语句,在weblogic的日志中执行没有结果,但是手动拷贝数据到客户端执行,却能够查到。这种奇怪的问题一下子就能引起我...

    jeanron100
  • Oracle基础知识-SQL简单命令

    SQL语句包括两个部分:1 DDL 数据定义语言 2 DML 数据控制语言 DDL: create:创建一个表 create table b( clob cha...

    用户1154259
  • 基本SQL语句(二)

    -- 数据的准备     -- 创建一个数据库     create database python_test charset=utf8;     -- ...

    对弈
  • Linux学习笔记之vim中的替换功能

    Jetpropelledsnake21
  • Oracle - 查询

    根据部门名称,查询雇员信息。部门名称存在于 DEPT 表中,其中的 DEPTNO 和 雇员表 EMP 中的 DEPTNO 对应。

    Carlos Ouyang
  • Oracle 多行、多列子查询

    本文使用到的是oracle数据库scott方案所带的表,scott是oracle数据库自带的方案,使用前请确保其解锁 ? 一、多行子查询 多行子查询子查询是嵌入...

    郑小超.
  • 第四届蓝桥杯决赛B组C/C++——空白格式化

    mathor
  • SQL 基础--> 子查询

    ORA-01427: single-row subquery returns more than one row

    Leshami

扫码关注云+社区

领取腾讯云代金券