隐式转换
隐式转换
Rocky-Wang 发表于2个月前
隐式转换
  • 发表于 2个月前
  • 阅读 1
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

oracle中,如果不同的数据类型之间关联,如果不显式转换数据,则它会根据以下规则对数据进行隐式转换

 

The following rules govern the direction in which Oracle makes implicit datatype conversions:

1) During INSERT and UPDATE operations, Oracle converts the value to the datatype of the affected column.
对于INSERT和UPDATE操作,oracle会把插入值或者更新值隐式转换为字段的数据类型。如
假如id列的数据类型为number
update t set id='1'; -> 相当于 update t set id=to_number('1');
insert into t(id) values('1') -> insert into t values(to_number('1'));

2) During SELECT FROM operations, Oracle converts the data from the column to the type of the target variable.
对于SELECT语句,oracle会把字段的数据类型隐式转换为变量的数据类型。如
假设id列的数据类型为varchar2
select * from t where id=1; -> select * from t where to_number(id)=1;
但如果id列的数据类型为number,则
select * from t where id='1'; -> select * from t where id=to_number('1');(参考下文)

3) When comparing a character value with a NUMBER value, Oracle converts the character data to NUMBER.
当比较一个字符型和数值型的值时,oracle会把字符型的值隐式转换为数值型。如
假设id列的数据类型为number
select * from t where id='1'; -> select * from t where id=to_number('1');

4) When comparing a character value with a DATE value, Oracle converts the character data to DATE.
当比较字符型和日期型的数据时,oracle会把字符型转换为日期型。如
假设create_date为字符型,
select * from t where create_date>sysdate; -> select * from t where to_date(create_date)>sysdate;(注意,此时session的nls_date_format需要与字符串格式相符)
假设create_date为date型,
select * from t where create_date>'2006-11-11 11:11:11'; -> select * from t where create_date>to_date('2006-11-11 11:11:11'); (注意,此时session的nls_date_format需要与字符串格式相符)

5) When you use a SQL function or operator with an argument of a datatype other than the one it accepts, 
Oracle converts the argument to the accepted datatype.
如果调用函数或过程等时,如果输入参数的数据类型与函数或者过程定义的参数数据类型不一直,则oracle会把输入参数的数据类型转换为函数或者过程定义的数据类型。如
假设过程如下定义 
p(p_1 number)
exec p('1'); -> exec p(to_number('1'));

6) When making assignments, Oracle converts the value on the right side of the equal sign (=) to the datatype of the target of the assignment on the left side.
赋值时,oracle会把等号右边的数据类型转换为左边的数据类型。如
var a number
a:='1'; - > a:=to_number('1');


7) During concatenation operations, Oracle converts from noncharacter datatypes to CHAR or NCHAR.
用连接操作符(||)时,oracle会把非字符类型的数据转换为字符类型。
select 1||'2' from dual; -> select to_char(1)||'2' from dual;

8) During arithmetic operations on and comparisons between character and noncharacter datatypes, 
Oracle converts from any character datatype to a number, date, or rowid, as appropriate. 
In arithmetic operations between CHAR/VARCHAR2 and NCHAR/NVARCHAR2, Oracle converts to a number.
如果字符类型的数据和非字符类型的数据(如number、date、rowid等)作算术运算,则oracle会将字符类型的数据转换为合适的数据类型,这些数据类型可能是number、date、rowid等。
如果CHAR/VARCHAR2 和NCHAR/NVARCHAR2之间作算术运算,则oracle会将她们都转换为number类型的数据再做比较。

9) Comparisons between CHAR/VARCHAR2 and NCHAR/NVARCHAR2 types may entail different character sets. 
The default direction of conversion in such cases is from the database character set to the national character set.

比较CHAR/VARCHAR2 和NCHAR/NVARCHAR2时,如果两者字符集不一样,则默认的转换方式是将数据编码从数据库字符集转换为国家字符集。


简单总结:
比较时,一般是字符型转换为数值型,字符型转换为日期型
算术运算时,一般把字符型转换为数值型,字符型转换为日期型
连接时(||),一般是把数值型转换为字符型,日期型转换为字符型
赋值、调用函数时,以定义的变量类型为准。

 

 

分类: Oracle

 

 

1     Oracle 隐式转换

Oracle中对不同类型的处理具有显式类型转换(Explicit)和隐式类型转换(Implicit)两种方式,对于显式类型转换,我们是可控的,但是对于隐式类型转换,当然不建议使用,
因为很难控制,有不少缺点,但是我们很难避免碰到隐式类型转换,如果不了解隐式类型转换的规则,那么往往会改变我们SQL的执行计划,从而可能导致效率降低或其它问题。

 

1.1  隐式转换发生场景

1.对于INSERTUPDATE操作,oracle会把插入值或者更新值隐式转换为字段的数据类型。

例如:

SQL> create table text(id varchar2(32),name varchar2(10),age number);

Table created.

SQL> insert into text values ('1','Jack','18');

1 row created.

SQL> update text set age='19';

1 rows updated.

SQL> select * from text;

        ID NAME              AGE

---------- ---------- ----------

         1 Jack               19

注:insert into text values ('1','Jack','18') 相当于 insert into text values(,’1’,’Jack’,to_number('18'))

update text set age='19'相当于update text set age=to_number('19')

 

2.当比较字符型和数值型的值时,oracle会把字符型的值隐式转换为数值型。例如:

SQL> explain plan for select * from text where age='19';

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

Plan hash value: 738342525

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |     2 |    66 |     2   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| TEXT |     2 |    66 |     2   (0)| 00:00:01 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("AGE"=19)

注:select * from text where age='19'相当于select * from text where age=to_number('19')

 

SQL> explain plan for select * from text where id=1;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

Plan hash value: 738342525

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |     1 |    38 |     2   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| TEXT |     1 |    38 |     2   (0)| 00:00:01 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter(TO_NUMBER("ID")=1)

注:select * from text where id=1;相当于select * from text where to_number(id)=1

如果id列建有索引此时将失效

 

3.当比较字符型和日期型的数据时,oracle会把字符型转换为日期型。例如:

 

SQL> create table table_date(varchar_date varchar2(20),date_date Date);

Table created.

SQL> insert into table_date values(to_char(sysdate,'yyyy-mm-dd'),sysdate);

1 row created.

SQL> select * from table_date;

VARCHAR_DATE         DATE_DATE

-------------------- ---------

2014-02-26           26-FEB-14

SQL> alter session set nls_date_format='yyyy-mm-dd hh24:mi:ss';

Session altered.

SQL> explain plan for select * from table_date where varchar_date

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

Plan hash value: 1510990824

--------------------------------------------------------------------------------

| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |            |     1 |    21 |     2   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| TABLE_DATE |     1 |    21 |     2   (0)| 00:00:01 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter(INTERNAL_FUNCTION("VARCHAR_DATE")

注:select * from table_date where varchar_date相当于

select * from table_date where to_date(varchar_date,’yyyy-mm-dd hh24:mi:ss’)

 

SQL> explain plan for select * from table_date where date_date>'2014-2-26 0:0:0';

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

Plan hash value: 1510990824

--------------------------------------------------------------------------------

| Id  | Operation         | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |            |     1 |    21 |     2   (0)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| TABLE_DATE |     1 |    21 |     2   (0)| 00:00:01 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter("DATE_DATE">TO_DATE(' 2014-02-26 00:00:00', 'syyyy-mm-dd

              hh24:mi:ss'))

 

注:select * from table_date where date_date>'2014-2-26 0:0:0'相当于

select * from table_date where date_date>to_date('2014-2-26 0:0:0’, ’yyyy-mm-dd hh24:mi:ss’

 

 


4. 隐式转换发正在字段列上时将使索引失效。例如:

 

1)当末发生隐式转换时索引有效

SQL> create table t1 as select OBJECT_ID as id ,to_char(OBJECT_ID) as vid from dba_objects;

Table created.

SQL> desc t1

 Name                                      Null?    Type

 ----------------------------------------- -------- ----------------------------

 ID                                                 NUMBER

 VID                                                VARCHAR2(40)

SQL> create index t1_ind_vid on t1(vid);

Index created.

SQL> explain plan for select * from t1 where vid='15612';

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

Plan hash value: 1215445203

------------------------------------------------------------------------------------------

| Id  | Operation                   | Name       | Rows  | Bytes | Cost (%CPU)| Time     |

------------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT            |            |     1 |    35 |     2   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| T1         |     1 |    35 |     2   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | T1_IND_VID |     1 |       |     1   (0)| 00:00:01 |

------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("VID"='15612')

注:未发生隐式转换正常执行索引扫

 


2)当字段列发生隐式转换时索引将失效

SQL> explain plan for  select * from t1 where vid=15612;

Explained.

SQL> select * from table(dbms_xplan.display);

PLAN_TABLE_OUTPUT

-------------------------------------------------------------------------------

Plan hash value: 3617692013

--------------------------------------------------------------------------

| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |      |     1 |    11 |    48   (5)| 00:00:01 |

|*  1 |  TABLE ACCESS FULL| T1   |     1 |    11 |    48   (5)| 00:00:01 |

--------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   1 - filter(TO_NUMBER("VID")=15612)

 

注:select * from t1 where vid=15612 相当于select * from t1 where to_number(vid)=15612,vid列发生隐式转换执行计划显示全表扫描末使用索引。

 

1.2  隐式转换的缺点

1. 使用显示类型转换会让我们的SQL更加容易被理解,也就是可读性更强,但是隐式类型转换却没有这个优点。


2. 隐式类型转换往往对性能产生不好的影响,特别是左值的类型被隐式转为了右值的类型。这种方式很可能使我们本来可以使用索引的而没有用上索引,也有可能会导致结
  果出错。


3. 隐式类型转换可能依赖于发生转换时的上下文环境,比如1中的to_date(sysdate,fmt),一旦上下文环境改变,很可能我们的程序就不能运行。


4. 隐式类型转换的算法或规则,以后Oracle可能改变,这是很危险的,意味着旧的代码很可能在新的Oracle版本中运行出现问题(性能、错误等),显示类型转换总是有最高
  的优先级,所以显示类型转换没有这种版本更替可能带来的问题。


5. 隐式类型转换是要消耗时间的,当然同等的显式类型转换时间也差不多,最好的方法就是避免类似的转换,在显示类型转换上我们会看到,最好不要将左值进行类型转换,到
  时候有索引也用不上索引,还要建函数索引,索引储存和管理开销增大。

 

 

小结

Oracle使用数据类型的优先级来决定隐式类型转换,原则是将优先级低的转换为优先级高的(数据类型优先级为:Number>字符类型>日期类型)。隐式转换发生在字
 段列上时将使索引失效。
 

共有 人打赏支持
粉丝 4
博文 25
码字总数 42306
×
Rocky-Wang
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: