Welcome 微信登录

首页 / 数据库 / MySQL / Oracle 实现基于函数的索引

使用场景:
当一个查询运行很慢。通过检查where子句,发现其中的一列应用了sql lower函数,lower函数阻止使用该列上现有的索引。你想要创建一个基于函数索引来支持这个查询,如下SQL> select index_name,column_name from user_ind_columns where table_name="T1";INDEX_NAME                COLUMN_NAME
------------------------- ------------------------------
T1_PK                   OBJECT_IDSQL> set autotrace trace explain;
SQL> select * from t1 where lower(object_name)="i_undo1";执行计划
----------------------------------------------------------
Plan hash value: 3617692013--------------------------------------------------------------------------
| Id  | Operation       | Name | Rows  | Bytes | Cost (%CPU)| Time   |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT  |      | 908 | 101K| 436 (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T1 | 908 | 101K| 436 (1)| 00:00:01 |
--------------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------- 1 - filter(LOWER("OBJECT_NAME")="i_undo1")
从以上可以看出即使该表中有索引也没有使用。解决方案
1、创建一个基于函数的索引
2、如果使用Oracle database 11g或更高版本,创建一个索引虚拟列下面实现基于函数的索引创建索引可以通过以下方式来估计索引所使用空间以及所需要分配的空间SQL> set serveroutput on
SQL> var used_bytes number;
SQL> var allo_bytes number;
SQL> exec dbms_space.create_index_cost("create index t1_object_name on t1(lower(object_name))",:used_bytes,:allo_bytes);
 
PL/SQL procedure successfully completed
used_bytes
---------
2269350
allo_bytes
---------
4194304SQL>create index idx_lower on t1(lower(object_name)) tablespace index_nocompress;SQL> select * from t1 where lower(object_name)="i_undo1";执行计划
----------------------------------------------------------
Plan hash value: 2274688371-------------------------------------------------------------------------------------------------
| Id  | Operation                         | Name      | Rows  | Bytes | Cost (%CPU)| Time   |
-------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT                    |         | 908 | 101K| 193 (0)| 00:00:01 |
| 1 |  TABLE ACCESS BY INDEX ROWID BATCHED| T1        | 908 | 101K| 193 (0)| 00:00:01 |
|*  2 | INDEX RANGE SCAN                  | IDX_LOWER | 363 |     |   3 (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------Predicate Information (identified by operation id):
--------------------------------------------------- 2 - access(LOWER("OBJECT_NAME")="i_undo1")注意:不能直接修改一个创建了基于函数索引的列。需要先删除索引,然后修改列,最后再重建索引。不然会报ora-30556错误(在要修改的列上已定义函数索引或位图联接索引)查看基于函数的索引定义dba/all/user_ind_expressionsSQL> select index_name,column_expression from user_ind_expressions;INDEX_NAME                COLUMN_EXPRESSION
------------------------- --------------------------------------------------
IDX_LOWER               LOWER("OBJECT_NAME")接着实现在虚拟列创建一个索引使用场景现在正使用一个基于函数的索引,但想要获得更好的性能,想将基于函数的索引替换为一个虚拟列,然后在虚拟列上创建索引(需要11g环境或更高版本)。SQL>alter table t1 add(lower_object_name generated always as (lower(object_name)) virtual);
SQL>create index idx_lower on t1(lower_object_name) tablespace index_nocompress;由Oracle索引来理解ArcSDE索引 http://www.linuxidc.com/Linux/2012-10/72184.htmOracle索引技术之如何建立最佳索引 http://www.linuxidc.com/Linux/2012-09/70996.htmOracle索引列NULL值引发执行计划该表的测试示例 http://www.linuxidc.com/Linux/2012-09/69938.htmOracle索引 主键影响查询速度 http://www.linuxidc.com/Linux/2011-12/48588.htmOracle索引扫描 http://www.linuxidc.com/Linux/2012-03/56644.htm更多Oracle相关信息见Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12本文永久更新链接地址