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

说起数据类型转换,在开发中如此,在数据库中也是如此,之前简单对比过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[]){
/*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代表的含义还是有很大差别。

我们来看看在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)

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

时间: 2024-10-28 17:29:10

从Java的类型转换看MySQL和Oracle中的隐式转换(二)的相关文章

MySQL和Oracle中的隐式转换

今天在处理一个问题的时候,需要根据其他部门提供的sql语句对一个表中的数据进行了筛查. 语句类似下面的形式 > SELECT MAX_LEVEL,LOGOUT_TIME,CURRENT_DATE AS NOWTIME,cn_master FROM t_test_october_back_a WHERE ID in ( 100, 200, 300, 400, 500) ; +-----------+---------------+------------+-----------+ | MAX_LE

ORACLE绑定变量隐式转换导致性能问题

   年后一次系统升级后,监控数据库的工具DPA发现数据库的Total Wait时间突然飙增,如下截图所示,数据库的总体等待时间对比升级前飙增了非常多 另 外就是发现出现了较多的等待事件,主要有latch: cache buffers chains. latch: shared pool .db file scattered read.根据这边的监控发现TOP SQL里面从升级前的0次变为了一天的一万多次(有些甚至更多),分析过后我们就找开发人员了解一下系统升级变跟的内容和改动 开 发人员坚定的

简单对比MySQL和Oracle中的一个sql解析细节

SQL的语法解析器是一个很强大的内置工具集,里面会涉及到很多的编译原理的相关知识,语法分析,词法分析..一大堆看起来很理论的东东,不过看起来枯燥之余,它们的价值也更加明显. 借用一下网络中的原话:如果我们考究一下历史,就会发现很多被称为程序设计大师的人都是编译领域的高手.写出第一个微型机上运行的Basic语言的比尔盖茨,设计出Delphi的Borland的"世界上最厉害的程序员", Sun的JAVA之父, 贝尔实验室的C++之父 起点提得有些高了,今天和大家分享的案例是一个很简单的sq

由一条create语句的问题对比mysql和oracle中的date差别

今天开发的同事提交过来一个sql变更,在部署的时候发现了一个问题. 语句是一个简单的create语句 CREATE TABLE `test_user` (   `openid` varchar(64) NOT NULL,   `amount` varchar(11) DEFAULT 0,   `create_time` datetime DEFAULT CURRENT_TIMESTAMP,   `update_time` datetime DEFAULT CURRENT_TIMESTAMP,  

MySQL和Oracle中的delete,truncate对比

在MySQL和Oracle中的delete,truncate还是存在着一些差别,明白了这些差别可能对于处理问题,理解问题会有一些帮助. 我们来简单通过一些测试来说明.我们创建两个表test_del,test_tru来对比delete,truncate的操作.我们有一个临时表t_fund_info大概有几百万的数据量. 创建test_del > create table test_del select *from t_fund_info; Query OK, 1998067 rows affect

oracle中 如何将拉丁文转换成中文

问题描述 oracle中 如何将拉丁文转换成中文 '???? 我也不知道这个拉丁文是什么意思,有没有哪位大神转换过啊,在线等 解决方案 这是拉丁文还是(乱码了)?确定这是拉丁文? 解决方案二: 这是拉丁文还是(乱码了)?确定这是拉丁文? 解决方案三: 这看上去是一种文字而不是乱码.什么意思嘛,你需要找翻译 解决方案四: oracle11汉字乱码的问题解决方法 鼠标右键"计算机"->"系统属性"->"高级系统设置"->"

Java基础之隐式转换vs强制转换_java

Java中,经常可以遇到类型转换的场景,从变量的定义到复制.数值变量的计算到方法的参数传递.基类与派生类间的造型等,随处可见类型转换的身影.Java中的类型转换在Java编码中具有重要的作用. 在定义变量时,有许多要注意的问题,一不小心就会出现损失精度或者不兼容类型等问题. 例如:     1.定义长整型数据时,必须加后缀l或L               long l =123456789012345L     2.定义单精度类型时(7-8位有效数字),必须加后缀 f 或 F         

Oracle中的数据类型隐式转换(implicit conversion)

和其他的关系型数据库一样,oracle中也能进行一些隐式的数据转换,这对我们写SQL语句有非常用,我们可以不必麻烦地手动转化很多类型的字符.虽然前面我们介绍了一些使用例如to_char,to_date的函数进行强制转换的方法,但是隐式转换也还是不错的. Oracle可以隐式地进行一些变量类别之间转化,例如从字符串转换到数值,看下面的例子. SQL> select ename,sal from emp where sal = '1100′;   ENAME SAL ------– ---- SMI

浅析JavaScript中的隐式类型转换

        这篇文章主要是对JavaScript中的隐式类型转换进行了详细分析介绍,需要的朋友可以过来参考下,希望对大家有所帮助 如果把通过函数或方法调用,明确的将某种类型转换成另一种类型称为显示转换 ,相反则称为隐式类型转换 .google和维基百科中没有找到"显示类型转换","隐式类型转换"的字眼.暂且这么称呼.   一. 运算中存在的隐式类型转换    1, "+"运算符     代码如下: var a = 11, b = '22';