隐式转换的替代方案不是万能的

Posted bisal(Chen Liu)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了隐式转换的替代方案不是万能的相关的知识,希望对你有一定的参考价值。

隐式转换相关的历史文章,

Oracle、SQL Server和MySQL的隐式转换异同

见识一下SQL Server隐式转换处理的不同

如何找到隐式转换的SQL?

从隐式转换案例,来挖掘开发人员的技能提升

浅谈显式转换和隐式转换

隐式转换的案例场景

一次有意思的错选执行计划问题定位

隐式转换之前谈的比较多了,这个问题如果单从功能测试上,不一定能发现,但是通过执行计划、静态扫描等,还是能找到一些端倪的,归根结底,还是不规范的设计和开发,导致出现的。

有些隐式转换能通过替代方案解决,例如创建函数索引、将左侧的表达式转换到右侧、更改字段类型、更改变量类型等,但是不是说所有的替代方案在所有场景都适用。

创建测试数据,

SQL> create table test_timestmap_date(c1 date, c2 timestamp);
Table Created.


SQL> insert into test_timestmap_date values(sysdate, systimestamp);
1 row created.


SQL> create index idx_test_timestmap_date_01 on test_timestmap_date(c1);
Index Created.


SQL> commit;
Commit Completed.

我们知道,如果是"where date = date",

SQL> select * from test_timestmap_date where c1=sysdate;
...

会使用到索引,

------------------------------------------------------------------------------------------------------------------
| Id  | Operation                           | Name                       | Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |                            |       |       |     1 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| TEST_TIMESTMAP_DATE        |     1 |    22 |     1   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN                  | IDX_TEST_TIMESTMAP_DATE_01 |     1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("C1"=SYSDATE@!)

如果是"where date = timestamp",右值优先级高,可以看到,左值使用了内部函数INTERVAL_FUNCTION,不会用到索引,

SQL> select * from test_timestmap_date where c1=systimestamp;
...


-----------------------------------------------------------------------------------------
| Id  | Operation         | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                     |       |       |     3 (100)|          |
|*  1 |  TABLE ACCESS FULL| TEST_TIMESTMAP_DATE |     1 |    22 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(SYS_EXTRACT_UTC(INTERNAL_FUNCTION("C1"))=SYS_EXTRACT_UTC(SYSTIMESTAMP(6)))

如果是varchar2、number,通常能通过to_number()函数作为方案让其能用到索引,但是针对date、timestamp类型的,to_timestamp()不会起作用。

如下所示,创建一个to_timestamp()的函数索引,强制将date转成timestamp类型,

SQL> create index idx_test_timestmap_date_02 on test_timestmap_date(to_timestamp(c1, 'yyyy-mm-dd hh24:mi:ss'));
Index Created.

但实际执行,仍采用全表扫描,

SQL> select * from test_timestmap_date where c2 = systimestamp;
...


-----------------------------------------------------------------------------------------
| Id  | Operation         | Name                | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |                     |       |       |     3 (100)|          |
|*  1 |  TABLE ACCESS FULL| TEST_TIMESTMAP_DATE |     1 |    22 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(SYS_EXTRACT_UTC(INTERNAL_FUNCTION("C2"))=SYS_EXTRACT_UTC(SYSTIMESTAMP(6)))

因此,针对这种场景,只能通过修改代码,将程序中的变量类型从timestamp改成date,或者将数据库中的字段类型从date改成timestamp,不能通过仅仅创建函数索引解决。

还是最开始说的,大多数隐式转换,是可以通过规范设计和开发,在投产前的环节进行规避,否则就只能等着出现问题,然后尝试各种替代方案了寻求解决了。

近期更新的文章:

SWIFT国际清算体系的科普贴

关于数据治理的读书笔记 - 理现状和定目标

MySQL何时需要手动刷新授权表

SQL Monitor中status的作用

基金A类和C类的科普贴

文章分类和索引:

公众号900篇文章分类和索引

以上是关于隐式转换的替代方案不是万能的的主要内容,如果未能解决你的问题,请参考以下文章

在 .NET 中使用隐式转换替代多重继承

Xcode 是不是将 plist 隐式转换为二进制格式?

JavaScript 类型隐式转换规律

Qt 中是不是有签名的“sizeof”替代方案

我对这种重复的替代解决方案是不是正确?

js的隐式类型转换你懂了嘛 一起来复习一下吧