索引是我们进行优化的一种重要方式。实际工作中,一个简单的索引,可能就会大大提升提高关键业务作业效率,最终提升用户满意度。在CBO时代,DBA和开发人员经常为索引为什么不出现在执行计划中而困惑。
问题提出
下面是一个模拟的开发场景。
//构建数据表
SQL> create table t as select * from dba_objects ;
Table created
SQL> create index idx_t_id on t(object_id);
Index created
SQL>create index idx_t_staus on t(status);
Index created
SQL> update t set status=to_char(length(owner));
51367 rows updated
SQL> commit;
Commit complete
SQL> desc t
Name Type Nullable Default Comments
-------------- ------------- -------- ------- --------
(篇幅所限,有省略…)
SUBOBJECT_NAME VARCHAR2(30) Y
OBJECT_ID NUMBER Y
STATUS VARCHAR2(7) Y
//数据分布
SQL> select status, count(*) from t group by status;
STATUS COUNT(*)
------- ----------
3 23655
6 24178
18 8
21 296
10 10
8 139
5 1358
7 787
14 381
2 554
4 1
下面我们执行一个简单的select查询,观察执行计划方案。
SQL> explain plan for select * from t wherestatus=14;
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 89 | 161 (4)| 00:00:02 |
|* 1 | TABLE ACCESS FULL| T | 1 | 89 | 161 (4)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("STATUS")=14)
13 rows selected
SQL> rollback;
Rollback complete
注意这个实验结果,我们在对应的status列上加入了索引,却没有执行索引路径。
此时,我们注意到实验的select语句中,where条件“status=14”,而数据表上该列的类型为varchar2(7)。那么,是不是这个原因引起的索引路径计划问题呢?
SQL> explain plan for select * from t where status='14';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1853254432
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)|
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 324 | 28836 | 11 (0)|
| 1 | TABLE ACCESS BY INDEX ROWID| T | 324 | 28836 | 11 (0)|
|* 2 | INDEX RANGE SCAN | IDX_T_STAUS | 324 | | 2 (0)|
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("STATUS"='14')
14 rows selected
SQL> rollback;
Rollback complete
进行简单的SQL修改之后,我们发现执行计划变化为我们希望的方式。原因是如何呢?在之前的执行计划中,存在“1 - filter(TO_NUMBER("STATUS")=14)”的部分。这说明在进行条件搜索的时候,Oracle发现类型不匹配,隐式的将数据列加入了一个to_number函数。这样,Oracle就需要一个如函数索引的索引列来支持搜索路径,于是索引idx_t_status的搜索成本就大大增加。经过试算,Oracle认为全表扫面的成本相对较低。
显然,这种情况是我们开发人员不希望看到的。我们已经付出了成本来构建维护索引,对关键用例功能不能支持,应该是我们避免的。其实,解决的方案也很容易,就是注意细节。在where条件书写的时候明确清楚属性列类型,这样就可以避免这种情况发生。
那么,是不是发生类型转换就一定不走索引呢?我们看下一个例子。
SQL> explain plan for select * from t where object_id='1000';
Explained
SQL> select * from table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 514881935
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Ti
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 89 | 2 (0)| 00
| 1 | TABLE ACCESS BY INDEX ROWID| T | 1 | 89 | 2 (0)| 00
|* 2 | INDEX RANGE SCAN | IDX_T_ID | 1 | | 1 (0)| 00
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("OBJECT_ID"=1000)
14 rows selected
SQL> rollback;
Rollback complete
例外出现了。Object_id类型为number,如果根据刚才我们的理论,where条件中出现的“object_id=’1000’”就不应该出现索引路径。这个是怎么回事呢?
我们观察到搜索的访问条件“2 - access("OBJECT_ID"=1000)”,说明语句生成执行计划的时候,输入条件已经转化为数字类型1000。所以生成的执行计划是不会被隐式类型转化所困扰。
那么,笔者猜想是在Oracle接受到查询语句之后,会有一个SQL改写的过程。在其中根据一些规则条件,对SQL进行改写优化。当Oracle发现这样简单的隐式类型转化后,会自主的将字符串1000转化为类型匹配的数字类型1000。这个例子就告诉我们,一些简单的隐式类型转化也是会走索引的。
最后要说一下发生隐式类型转化的开发场景。在开发中,通常我们要避免出现隐式类型转换,要把SQL语句的细节准备好。无论是前端代码开发,还是后台大作业编写,都要把握好类型匹配的情况。避免出现潜在的性能风险。
相关推荐
### C语言隐式类型转换规则详解 #### 一、引言 C语言作为一种广泛使用的编程语言,具有严格的类型检查机制。在C语言中,不同类型的数值可以通过类型转换来进行混合运算。这种转换分为两种:隐式类型转换和显式类型...
这种转换通常分为两种类型:转换构造函数和成员转换函数,这两种方法都遵循C++的隐式类型转换规则。 首先,转换构造函数是一种特殊的构造函数,它的作用是将非本类类型的对象转换成本类的对象。在给定的代码示例中...
"隐式类型转换" 隐式类型转换是C语言中的一种重要概念,它指的是在编译时由编译程序按照一定规则自动完成的数据类型转换。这种转换在C语言的表达式中经常出现,当不同类型的数据参与同一运算时,编译器就会按照规定...
数据类型的隐式转换 数据类型的隐式转换是计算机编程中一个重要的概念,它指的是在编程语言中,编译器或解释器自动将一种数据类型转换为另一种数据类型的过程。这种转换可以是隐式的,也可以是显式的。数据类型的...
JavaScript中的隐式类型转换是其弱类型特性的重要体现,它允许不同数据类型的值在运算时进行自动转换,但这也可能导致一些意料之外的结果。在JavaScript中,数据类型包括字符串(String)、数字(Number)、布尔(Boolean...
本文将详细探讨“前端面试题之baseJS-==隐式类型转换”这一主题,帮助你掌握JavaScript中的类型转换规则,以便在面试中能够自信地解答相关问题。 在JavaScript中,“==”双等号运算符用于比较两个值是否相等。然而...
在C++编程语言中,隐式类型转换(Implicit Type Conversion)是一种编译器自动进行的数据类型转换,通常发生在不需要程序员明确指定的情况下。这种转换在某些操作中是允许的,但可能会导致意料之外的结果,因此需要...
JavaScript中的隐式类型转换是开发者在编写代码时经常会遇到的一个陷阱,尤其在面试中,它经常作为考察开发者对语言理解深度的问题出现。本篇主要探讨的是JavaScript中的隐式类型转换,特别是那些容易出错的实例代码...
不同类型的变量比较要先转类型,叫做类型转换,类型转换也叫隐式转换。隐式转换通常发生在运算符加减乘除,等于,还有小于,大于等。。 typeof '11' //string typeof(11) //number '11' < 4 //false 本章节单独...
本文主要讨论了 Java 中的三种类型转换:强制类型转换、自动升级类型转换以及表达式的升级类型转换,同时也提到了自动包装和解包的概念。 1. 强制类型转换: 强制类型转换是程序员明确指定将一个数据类型转换为另...
转换分为两种主要类型:隐式转换(implicit conversion)和显式转换(explicit conversion),这两种转换都有其特定的规则和应用场景。 **26.1 隐式转换** 隐式转换是指C#编译器自动执行的转换,无需程序员进行...
Scala中的隐式类型转换的实现 Scala中的隐式类型转换是Scala语言中的一种强大语言特性,可以自动进行某些数据类型的隐式转换。隐式类型转换可以分为两种:隐式参数和隐式转换。下面将对这两种类型进行详细的介绍。 ...
- **避免在索引字段上使用可能导致转换的表达式**:如在`WHERE`子句中使用函数处理索引字段,可能导致索引失效。 - **使用`CAST`或`CONVERT`函数**:当确实需要类型转换时,使用这两个函数可以明确控制转换过程,...
当我们在查询的时候,使用到的索引发生了隐式类型转换,也会导致索引失效。例如,SELECT * FROM table WHERE column = '123',这里column是int类型,但是在查询的时候使用了字符串类型的比较,导致索引失效。解决方法...
在C++编程语言中,`operator type()` 是一种特殊的成员函数,称为隐式类型转换运算符,它允许类的对象能够被隐式地转换为其他类型,包括基本数据类型或者自定义类类型。这个功能在处理类对象需要与其他类型兼容或者...
### C#中的显式类型与隐式转换 在C#编程语言中,类型转换是非常重要的一个概念,它涉及数据类型的转换以及如何确保程序能够正确处理不同类型的数据。本文将基于提供的内容,详细介绍C#中几种常见的类型转换方法及其...