如何创建oracle函数索引
Oracle8i的很重要的一个新特性就是增加了function-based index这种索引类型(后面简称为FBI)。
有了这个特性后,Oracle DBA就可以在索引中使用函数或者表达式了。这些函数可以使Oracle自己的函数,
也可以使用户自己的PL/SQL函数等。
DBA在SQL语句调优的过程中遇到的一个很常见的问题就是,如何优化那些在WHERE子句中使用了函数的语句。
因为在以前,在WHERE子句中使用函数会使在这个表上创建的索引没法利用,从而难以提高这个语句的性能。
例子:
使用基于成本的优化器,索引为标准的B树索引,建立在SURNAME列上。
SQL>create index non_fbi on sale_contacts (surname);
SQL>analyze index non_fbi compute statistics;
SQL>:analyze table sale_contacts compute statistics;
SQL>SELECT count(*) FROM sale_contacts
WHERE UPPER(surname) = 'ELLISON';
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=3 Card=1 Bytes=17)
1 0 SORT (AGGREGATE)
2 1 TABLE ACCESS (FULL) OF 'SALES_CONTACTS' (Cost=3 Card=16 Bytes=272)
从SQL*PLUS的autotrace产生的执行路径可以看到,虽然我们在WHERE子句中用到的SURNAME列上创建了索引,但是仍然执行的是全表扫描。如果这张表很大的话,这回消耗大量的时间。
现在我们试着建立一个FBI索引:
SQL>create index fbi on sale_contacts (UPPER(surname));
SQL>analyze index fbi compute statistics;
SQL>analyze table sale_contacts compute statistics;
SQL>SELECT count(*) FROM sale_contacts WHERE UPPER(surname) = 'ELLISON';
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=17)
1 0 SORT (AGGREGATE)
2 1 INDEX (RANGE SCAN) OF 'FBI' (NON-UNIQUE) (Cost=2 Card=381 Bytes=6477)
从SQL*Plus返回的执行计划我们可以看到,这次,Oracle对表不再全表扫描,而是先扫描索引,因为优化器可以知道FBI索引得存在。
使用FBI索引所能够带来的性能提升取决于表的大小、表中重复记录的量、在WHERE子句中使用的列等因素。
有一点需要清楚,FBI索引并不真正在索引里边存储了表达式的结果,而是使用了一个“表达树”(expression tree)。
由优化器来对SQL语句中的表达式进行解析,并且和FBI索引上面的表达式进行对比。这里,SQL函数的大小写时敏感的。
因此要求SQL语句中使用的函数和创建FBI索引得时候的那个SQL函数的大小写一致,否则无法利用这个FBI索引。
因此,在编程的时候要有一个良好的编程风格。
Init.ora里边需要修改的参数
下面这几个参数必须在init.ora里边指定:
QUERY_REWRITE_INTEGRITY = TRUSTED
QUERY_REWRITE_ENABLED = TRUE
COMPATIBLE = 8.1.0.0.0 (or higher)
授权:
要使一个用户能够创建FBI索引,他必须被授予以下权限:CREATE INDEX和QUERY REWRITE,或者CREATE ANY INDEX和GLOBAL QUERY REWRITE这两个权限。
索引的使用者必须能够有那个FBI索引上使用的那个函数的执行权限。如果没有相应的权限,那么这个FBI索引得状态将变成DISABLED(DBA_INDEXES)。
如果那个FBI索引得状态是DISABLED,那么DBA可以这样来处理:
a:删除并重建
B:ALTER INDEX index_name ENABLED。这个Enabled只能对FBI索引使用。
C:ALTER INDEX UNUSABLE;
注意:如果一个查询中使用到了这个索引,但是这个FBI索引的状态是DISABLED,但是优化器选择了使用这个索引,那么将会返回一个Oracle错误。
例子:
ORA error:
ERROR at line 1: ORA-30554: function-based index MYUSER.FBI is disabled.
而且,一旦这个FBI索引的状态是Disabled,那么这张表上所有涉及索引列的DML操作也将失败。除非这个索引得状态变成UNUSABLE,而且在初始化参数里边指定SKIP_UNUSABLE_INDEXES为TRUE。
一些例子:
SQL>CREATE INDEX expression_ndx
ON mytable ((mycola + mycolc) * mycolb);
SQL>SELECT mycolc FROM mytable
WHERE (mycola + mycolc) * mycolb
复合索引的例子:
SQL>CREATE INDEX example_ndx
ON myexample (mycola, UPPER(mycolb), mycolc);
SQL>SELECT mycolc FROM myexample
WHERE mycola = 55 AND UPPER(mycolb) = 'JONES';
限制和规则总结:
对于下面这些限制,不能创建FBI索引:
a) LOB 列
b) REF
c) Nested table 列
d) 包含上面数据类型的对象
FBI索引必须遵守下面的规则:
a) 必须使用基于成本的优化器,而且创建后必须对索引进行分析
b) 不能存储NULL值。因为任何函数在任何情况下都不能返回NULL值。
c)如果一个用户定义的PL/SQL例程失效了,而且这个例程被FBI索引用到了,那么相应的这个FBI索引会变成DISABLED
d)创建FBI索引得函数必须是确定性的。即,对于指定的输入,总是会返回确定的结果。
e) 索引的属主如果没有了在FBI索引里面使用的函数的执行权限,那么这个FBI索引会变成DISABLED.
f) 在创建索引得函数里面不能使用SUM等总计函数。
g)要把一个DISABLED了的索引重新变成ENABLED,这个函数必须首先是ENABLED的才可以。
================================================================================================
这个语句还能优化嘛?
原语句:
select b.*
from test1 a,test2 b
where a.sflag ='-3'
and instr(','||a.id||',',','||b.certiid||',')>0;
通过执行发现test2表执行了全表扫描,需要120秒通过分析发现是test2的certiid列上实际上是有索引的。
但是它不能使用这个索引,不能通过索引的ROWID来搜索表,因为这里并没有b.certiid等于的条件,而是通过
条件instr(','||a.id||',',','||b.certiid||',')>0进行的连接。
然后考虑到需要返回的值是B.*而索引只包含了CERTIID列,索引INDEX FAST SCAN也用不到。
所以我们这里考虑修改如下:
select * from test2 where certiid in(
select b.certiid
from test1 a,test2 b
where a.sflag ='-3'
and instr(','||a.id||',',','||b.certiid||',')>0);
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID gsha1gj68gacg, child number 0
-------------------------------------
select /*+ gather_plan_statistics */ * from test2 where certiid in (select
b.certiid from test1 a, test2 b where a.sflag = '-3' and
instr(',' || a.id || ',', ',' || b.certiid || ',') > 0)
Plan hash value: 4074250259
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
----------------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 54 |00:00:32.69 | 133K|
| 1 | NESTED LOOPS | | 1 | 1 | 54 |00:00:32.69 | 133K|
| 2 | VIEW | VW_NSO_1 | 1 | 1 | 54 |00:00:32.69 | 133K|
| 3 | HASH UNIQUE | | 1 | 1 | 54 |00:00:32.69 | 133K|
| 4 | NESTED LOOPS | | 1 | 1 | 54 |00:00:28.67 | 133K|
| 5 | TABLE ACCESS BY INDEX ROWID| test1 | 1 | 1 | 38 |00:00:00.01 | 49 |
|* 6 | INDEX RANGE SCAN | INDEX_SFLAG | 1 | 1 | 38 |00:00:00.01 | 3 |
|* 7 | INDEX FAST FULL SCAN | PK_test2 | 38 | 24575 | 54 |00:00:25.65 | 133K|
| 8 | TABLE ACCESS BY INDEX ROWID | test2 | 54 | 1 | 54 |00:00:00.01 | 167 |
|* 9 | INDEX UNIQUE SCAN | PK_test2 | 54 | 1 | 54 |00:00:00.01 | 113 |
----------------------------------------------------------------------------------------------------
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
6 - access("A"."SFLAG"='-3')
7 - filter(INSTR(','||"A"."ID"||',',','||"B"."CERTIID"||',')>0)
9 - access("CERTIID"="$nso_col_1")
这里使用了一个子查询,子查询中使用的条件不是B.*而是B.certiid.可以看到这里使用了 INDEX FAST FULL SCAN,相当于把
索引当表来进行扫描,不考虑索引的结构。但是这里的一列的‘表’比所有字段的表要小得多所以也加快了查询。
修改后得语句任然有性能问题,看到这里的
INDEX FAST FULL SCAN | PK_test2 | 38
在NESTED LOOP的机制下运行了38次。本来想通过HASH JION来代替NESTED LOOPS 但是这里条件是INSTR(','||"A"."ID"||',',','||"B"."CERTIID"||',')>0,所以不好修改了。
修改后语句运行的时间由120秒降低到48秒,不知道还有优化的方法没?
原执行计划:
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 1212030027
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 3943K| 1921M| 1384K (1
| 1 | NESTED LOOPS | | 3943K| 1921M| 1384K (1
| 2 | TABLE ACCESS BY INDEX ROWID| test1 | 71 | 1278 | 5 (0
|* 3 | INDEX RANGE SCAN | INDEX_SFLAG | 71 | | 3 (0
|* 4 | TABLE ACCESS FULL | test2 | 55470 | 26M| 19504 (1
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("A"."SFLAG"='-3')
4 - filter(INSTR(','||"A"."ID"||',',','||"B"."CERTIID"||',')>0)
17 rows selected
http://www.itpub.net/thread-1477884-1-9.html
分享到:
相关推荐
Oracle支持多种类型的索引: - **B树索引(B-Tree Index)**: 最常见的索引类型,适用于等值查询,根据索引键的排序顺序查找数据。 - **位图索引(Bitmap Index)**: 适合于在含有大量重复值的列上,尤其是在进行...
3. **函数操作**: 如果在索引列上使用了函数,比如`SELECT * FROM t WHERE lower(column) = 'value'`,Oracle将不会使用索引,除非你为该函数创建了函数索引。这是因为函数操作改变了原始列的值,使得索引无法直接...
- Function-Based索引:基于函数的结果创建索引,索引列是函数的输出。 - Reverse索引:反向键索引,用于存储数据的反向副本,提高某些查询性能。 - Unique索引:确保列中的值是唯一的。 - Index-Organized ...
函数索引(Function-Based Index, FBI),是Oracle数据库自Oracle 8i版本引入的一种特殊类型的索引。它允许在创建索引时使用任意内置或用户自定义的函数对表中的列进行处理,从而为特定的查询条件提供更高效的访问...
### ORACLE CRC32函数详解 #### 一、概述 在Oracle数据库中,`CRC32`函数是一种非常实用的功能,主要用于将字符类型的数据转换为一个唯一的数字类型,这一过程通常被称为散列(Hash)。通过该函数,可以方便地生成...
"Oracle函数大全(CHM格式).rar"这个压缩包显然包含了关于Oracle数据库中各种函数的详细信息,对于学习和查询Oracle函数是非常宝贵的资源。 CHM(Compiled Help Manual)格式是一种由Microsoft开发的帮助文件格式...
Oracle提供了多种类型的索引,包括B树索引、位图索引、函数索引、唯一索引和复合索引等,每种都有其独特的应用场景和优缺点。 1. **B树索引**:这是最常见的索引类型,适用于频繁的查询操作。B树索引通过排序的数据...
索引优化方法有多种,包括重新设计索引、避免系统排序和使用函数索引等。重新设计索引可以避免全表扫描操作,降低资源消耗,缩短执行时间。避免系统排序可以减少排序操作的时间和空间消耗。使用函数索引可以提高查询...
4. 函数索引:基于列上的函数结果创建的索引,可用于优化包含函数的查询。 5. 唯一索引:确保索引列中的每个值都是唯一的,有助于保证数据的唯一性。 6. 复合索引:包含多个列的索引,适用于多个列组合的查询。 7. ...
### ORACLE操作XML函数 #### 一、XMLTYPE_instance与XPath_string 在Oracle数据库中,`XMLTYPE`是一种专门用于存储XML数据的数据类型。通过使用`XMLTYPE`字段,可以有效地管理和查询XML文档。其中,`XPath_string`...
本篇文章将深入探讨Oracle中的B*Tree索引、反向索引、降序索引、位图索引和函数索引。 1. **B*Tree索引**: - B*Tree索引是Oracle中最常见的索引类型,其结构类似于二叉树,可以高效地处理高基数数据列,即具有...
在数据库领域,Oracle和PostgreSQL都是非常知名的开源关系型数据库管理...然而,全面的兼容性不仅限于函数层面,还需要考虑SQL语法、存储过程、触发器、索引、分区表等方面,这需要根据实际情况进行深入研究和规划。
Oracle字符相似度函数是Oracle数据库系统提供的一种功能,用于评估两个字符串之间的相似性。这个功能在数据清洗、信息检索、文本分析等领域具有广泛的应用。在SQL查询中,我们可以直接使用这些函数来比较不同字符串...
### Oracle索引机制分析 #### 1. 基本索引概念 索引是数据库管理系统(DBMS)为了加快数据检索速度而采用的一种数据结构。Oracle提供了多种类型的索引,每种索引都有其特定的优势和适用场景。索引的基本目的是通过...
Oracle 分区与索引是数据库管理系统中用于优化大数据查询的关键技术。Oracle 分区是一种将大表和索引分成可管理的小部分,以提高查询效率、维护性和可用性。这种技术适用于处理海量数据,通过将数据分散到不同的存储...
Oracle支持多种索引类型,包括B*Tree索引、反向索引、降序索引、位图索引、函数索引等。每种索引都有其独特的适用场景和优缺点,了解并合理应用这些索引,对优化Oracle数据库性能至关重要。 #### 二、B*Tree索引...
### Oracle中的索引详解 #### 一、ROWID的概念 ROWID是一种特殊的数据类型,用于存储行在数据文件中的具体位置。它是一个64位编码的数据,由字符`A-Z`、`a-z`、`0-9`、`+`和`/`组成。在Oracle数据库中,ROWID用于...
- 函数索引:基于函数结果创建索引,支持更复杂的查询条件。 二、选择合适的索引策略 1. 单列索引:针对单个列创建的索引,适合频繁的等值查询。 2. 复合索引:包含多个列,适用于多列联合查询。 3. 唯一索引:...
函数索引(Function-Based Index,简称FBI):函数索引允许在索引创建时应用函数,即索引基于函数计算的结果而不是原始列值。这种索引适用于那些需要在查询中频繁使用表达式的情况,通过预计算表达式的值并建立...
首先,索引分为几种主要类型,包括B树索引、位图索引、函数索引和全局唯一索引等。B树索引是最常见的一种,其内部结构由根块、分支块和叶子块组成。在提供的内容中,我们看到了类似B树结构的分布模式,这可能是在...