全文索引性能分析

一个表建立了全文索引后,会不会导致性能的下降,一直是我比较关心的问题。这里对这个问题进行简单的讨论。

 

一个表建立了全文索引,是希望通过全文索引来提高表的查询性能,使得原本只能通过LINK ‘%’ 的查询,变得可以通过全文索引的扫描而快速得到查询结果。

使 用全文索引并不是简单的增加了一个索引那么简单。首先,全文索引导致磁盘资源的大量占用。全文索引本身就是一个利用磁盘空间换取性能的方法。而且,全文索 引的索引同步,索引定期维护,以及表本身的维护操作使得这个表的管理成本大大的增加。最重要的一点,使用全文索引并不是对应用透明的。如果要想利用全文索 引,必须修改查询语句。原有的查询语句是不可能利用全文索引的,需要改成全文索引规定的语法。

如果付出了这么大的代价,而得不到性能的提示,甚至导致性能有所下降,未免得不偿失。好在全文索引的使用,必须通过指定操作,比如CONTAINSCATSEARCHMARCH 等,这就是说,全文索引不会影响到其他的SQL 语句。

那么剩下的问题就是全文索引能否解决好它本身的问题了。首先考虑的一个问题就是,如果查询一个常用字会不会导致全文索引返回大量的记录,从而导致性能低下。这个问题可以通过添加停用词来解决。但是停用词本身也有问题,查询英文的停用词还好说,如果仅查询中文的停用词,Oracle 直接报错。这就又需要开发的配合,如异常捕获等。

如果不使用停用词的话,那么Oracle 能否保证在恰当的时候使用全文索引就是问题的关键。

还有一个问题,Oracle 一般优先考虑域索引,对于能通过其他索引快速得到结果的情况,Oracle 是否能作出正确的判断?

上面是仅包含一个全文索引的情况,如果一张表中建立了两个全文索引,那么Oracle 能否正确的选择索引吗?

还有,如果两张表进行关联,而又对两张表的两个字段都进行了全文索引的查询,那么是否会影响查询的效率。

此外,CTXCAT 索引包含一个索引集的概念,可以向索引集中添加其他字段,来提高全文索引处理复合查询的性能。不过,这种方法一是要消耗大量的磁盘空间,二是不能替代添加字段本身的索引,那么CTXCAT 索引和其他索引的配合使用与使用CTXCAT 索引集的性能差别有多大呢,这也是值得关注的地方。

这篇文章对全文索引可能存在的性能问题进行了简单的分析,下面打算通过几篇系列文章对上面的一些问题进行详细的描述。

 

首先建立测试环境:

SQL> CREATE TABLE T
2 (ID NUMBER PRIMARY KEY, NAME VARCHAR2(4000),
3 CREATED DATE, TYPE VARCHAR2(18), STATUS VARCHAR2(7));

表已创建。

SQL> INSERT INTO T
2 SELECT ROWNUM, OWNER || ' ' || OBJECT_NAME, CREATED, OBJECT_TYPE, STATUS
3 FROM DBA_OBJECTS;

已创建31313 行。

SQL> CREATE BITMAP INDEX IND_B_T_TYPE ON T(TYPE);

索引已创建。

SQL> CREATE BITMAP INDEX IND_B_T_STATUS ON T (STATUS);

索引已创建。

SQL> CREATE INDEX IND_T_CREATED ON T(CREATED);

索引已创建。

SQL> CREATE INDEX IND_T_NAME ON T (NAME) INDEXTYPE IS CTXSYS.CONTEXT;

索引已创建。

SQL> ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD';

会话已更改。

SQL> SET AUTOT ON

下面测试一下不包含全文索引查询的SQL

SQL> SELECT * FROM T WHERE ID = 31255;

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
31255 TEST ARTICLES_TAB 2006-11-09 TABLE VALID

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=2040)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=2040)
2 1 INDEX (UNIQUE SCAN) OF 'SYS_C007810' (UNIQUE) (Cost=1 Card=100)

SQL> SELECT * FROM T WHERE NAME LIKE '%SELE%' AND CREATED >= TO_DATE('2006-7-1');

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
26405 SELE SEQ_MANUFACTURE_CODE 2006-07-04 SYNONYM VALID
25918 SELE CAT_ATC 2006-07-06 SYNONYM VALID
25920 SELE CAT_ATC_DOSEAGE 2006-07-06 SYNONYM VALID
25921 SELE CAT_ATC_DRUG 2006-07-06 SYNONYM VALID
26406 SELE SEQ_SALER_CODE 2006-07-06 SYNONYM VALID
25919 SELE CAT_ATC_CATEGORY 2006-07-06 SYNONYM VALID

已选择6 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=10 Card=55 Bytes=112200)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=10 Card=55 Bytes=112200)
2 1 INDEX (RANGE SCAN) OF 'IND_T_CREATED' (NON-UNIQUE) (Cost=2 Card=198)

从测试结果上看,全文索引对其他的查询语句没有影响,其实这个结果是意料之中的,因为只有包含了指定的查询操作(如CONTAINSCATSEARCHMARCHES 等)才会用到全文索引。

下面看一下全文索引的表现:

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'OUTLN') > 0;

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
25894 OUTLN ORA$GRANT_SYS_SELECT 2005-09-21 PROCEDURE VALID
25893 OUTLN OL$SIGNATURE 2005-09-21 INDEX VALID
.
.
.
6788 SYS DBMS_OUTLN_LIB 2005-09-21 LIBRARY VALID

已选择15 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=2047)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=2047)
2 1 DOMAIN INDEX OF 'IND_T_NAME' (Cost=0)

统计信息
----------------------------------------------------------
16 recursive calls
0 db block gets
39 consistent gets
0 physical reads
0 redo size
996 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
15 rows processed

Oracle 在进行全文索引的查询时,会使用全文索引的。但是同时从统计信息上也可以看到,无论是第几次执行SQLrecursive calls 这一项都不会是0 值。这是由于处理全文索引,Oracle 要在内部调用一些存储过程。因此,即使查询结果很小,也会导致较大的逻辑读。

下面看看同时包括全文索引查询和主键查询的情况:

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'SYS') > 0 AND ID = 10000;

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
10000 SYS V_$BACKUP_SET 2005-09-21 VIEW VALID

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=4 Card=1 Bytes=2047)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=4 Card=1 Bytes=2047)
2 1 BITMAP CONVERSION (TO ROWIDS)
3 2 BITMAP AND
4 3 BITMAP CONVERSION (FROM ROWIDS)
5 4 INDEX (RANGE SCAN) OF 'SYS_C007810' (UNIQUE) (Cost=1 Card=22054)
6 3 BITMAP CONVERSION (FROM ROWIDS)
7 6 SORT (ORDER BY)
8 7 DOMAIN INDEX OF 'IND_T_NAME' (Cost=0 Card=22054)

统计信息
----------------------------------------------------------
93 recursive calls
0 db block gets
258 consistent gets
0 physical reads
0 redo size
531 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed

从测试的结果上可以看到,Oracle 更偏向使用全文索引,明明通过主键可以快速的找到记录,而Oracle 偏要将全文索引扫描结果和主键扫描结果都转化为BITMAP ,然后进行BITMAP AND 操作,最终在转化回ROWID

不过上面的这个执行计划也不难理解,Oracle 认为全文索引的扫描代价是0 ,而主键的扫描代价是1 ,因此才产生了如此的执行计划。

从统计信息上看,这个执行效果并不好。不过,这并不能认为是Oracle 的问题,因为目前为止,还没有对表和索引进行分析。

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T')

PL/SQL 过程已成功完成。

SQL> EXEC DBMS_STATS.GATHER_INDEX_STATS(USER, 'IND_T_NAME')

PL/SQL 过程已成功完成。

SQL> EXEC DBMS_STATS.GATHER_INDEX_STATS(USER, 'IND_T_CREATED')

PL/SQL 过程已成功完成。

SQL> EXEC DBMS_STATS.GATHER_INDEX_STATS(USER, 'IND_B_T_STATUS')

PL/SQL 过程已成功完成。

SQL> EXEC DBMS_STATS.GATHER_INDEX_STATS(USER, 'IND_B_T_TYPE')

PL/SQL 过程已成功完成。

对表和索引进行了分析之后,再来执行一下刚才的查询:

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'SYS') > 0 AND ID = 10000;

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
10000 SYS V_$BACKUP_SET 2005-09-21 VIEW VALID

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=56)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=56)
2 1 INDEX (UNIQUE SCAN) OF 'SYS_C007810' (UNIQUE) (Cost=1 Card=31313)

统计信息
----------------------------------------------------------
10 recursive calls
0 db block gets
14 consistent gets
0 physical reads
0 redo size
531 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1 rows processed

Oracle 这次选择了正确的执行计划,通过主键的唯一扫描,找到了记录。同时可以发现,recursive calls 仍然不为0

要想得到CONTAINS(NAME, 'SYS') > 0 的结果,仅仅靠扫描表是不行的,必须通过全文索引机制才能得到答案。这里Oracle 处于代价的考虑选择了主键扫描,但是为了得到CONTAINS 操作的结果,Oracle 必须要对查询中CONTAINS 操作进行全文索引处理。这就是recursive calls 不为0 的原因。

Oracle 处理全文索引查询一般就是上面的两种情况,一种是通过全文索引的直接扫描,另一种是通过其他执行计划获得ROWID ,再去比较这个ROWID 是否满足全文索引查询的要求。

在看一个例子:

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'OUTLN') > 0 AND ID > 15;

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
25894 OUTLN ORA$GRANT_SYS_SELECT 2005-09-21 PROCEDURE VALID
25893 OUTLN OL$SIGNATURE 2005-09-21 INDEX VALID
25892 OUTLN OL$NODES 2005-09-21 TABLE VALID
25891 OUTLN OL$NAME 2005-09-21 INDEX VALID
25890 OUTLN OL$HNT_NUM 2005-09-21 INDEX VALID
25889 OUTLN OL$HINTS 2005-09-21 TABLE VALID
25888 OUTLN OL$ 2005-09-21 TABLE VALID
21315 PUBLIC OUTLN_PKG 2005-09-21 SYNONYM VALID
20757 PUBLIC DBMS_OUTLN_EDIT 2005-09-21 SYNONYM VALID
20756 PUBLIC DBMS_OUTLN 2005-09-21 SYNONYM VALID
9194 SYS OUTLN_PKG 2005-09-21 PACKAGE BODY VALID
9193 SYS OUTLN_PKG 2005-09-21 PACKAGE VALID
9192 SYS OUTLN_EDIT_PKG 2005-09-21 PACKAGE BODY VALID
9191 SYS OUTLN_EDIT_PKG 2005-09-21 PACKAGE VALID
6788 SYS DBMS_OUTLN_LIB 2005-09-21 LIBRARY VALID

已选择15 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=7 Card=15 Bytes=840)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=7 Card=15 Bytes=840)
2 1 DOMAIN INDEX OF 'IND_T_NAME' (Cost=2)

统计信息
----------------------------------------------------------
16 recursive calls
0 db block gets
39 consistent gets
0 physical reads
0 redo size
996 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
15 rows processed

这个例子中,如果使用主键扫描则代价太大,Oracle 在这里选择了全文索引的扫描。看来通过收集统计信息是有助于Oracle 找到正确的执行计划。

 

 

测试环境仍然沿用上一篇文章介绍的。下面看一下这个查询语句:

SQL> SELECT * FROM T
2 WHERE CONTAINS(NAME, 'SYS') > 0
3 AND STATUS = 'INVALID';

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
5942 SYS ALL_REPPARAMETER_COLUMN 2005-09-21 VIEW INVALID
6319 SYS DBA_LOGSTDBY_LOG 2005-09-21 VIEW INVALID
.
.
.
10332 SYS _ALL_REPRESOLUTION 2005-09-21 VIEW INVALID

已选择19 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=28 Card=7103 Bytes=397768)
1 0 TABLE ACCESS (FULL) OF 'T' (Cost=28 Card=7103 Bytes=397768)

统计信息
----------------------------------------------------------
57 recursive calls
0 db block gets
373 consistent gets
0 physical reads
0 redo size
1471 bytes sent via SQL*Net to client
375 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
19 rows processed

由于包含SYS 的记录太多,因此Oracle 没有选择全文索引,但是Oracle 为什么没有使用BITMAP 索引呢,这主要是由于确实列的直方图分析。

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS(USER, 'T', METHOD_OPT => 'FOR ALL INDEXED COLUMNS SIZE 254')

PL/SQL 过程已成功完成。

SQL> SELECT * FROM T
2 WHERE CONTAINS(NAME, 'SYS') > 0
3 AND STATUS = 'INVALID';

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
5942 SYS ALL_REPPARAMETER_COLUMN 2005-09-21 VIEW INVALID
6319 SYS DBA_LOGSTDBY_LOG 2005-09-21 VIEW INVALID
.
.
.
10332 SYS _ALL_REPRESOLUTION 2005-09-21 VIEW INVALID

已选择19 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=10 Card=19 Bytes=1064)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=10 Card=19 Bytes=1064)
2 1 BITMAP CONVERSION (TO ROWIDS)
3 2 BITMAP INDEX (SINGLE VALUE) OF 'IND_B_T_STATUS'

统计信息
----------------------------------------------------------
57 recursive calls
0 db block gets
117 consistent gets
0 physical reads
0 redo size
1471 bytes sent via SQL*Net to client
375 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
19 rows processed

收集了列的直方图信息,Oracle 采用了BITMAP 索引,使得查询效率提到。

下面看几个查询:

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'SYS') > 0
2 AND STATUS = 'INVALID'
3 AND TYPE = 'PROCEDURE';

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
6735 SYS DBMS_LOGMNR_FFVTOLOGMNRT 2005-09-21 PROCEDURE INVALID
6741 SYS DBMS_LOGMNR_OCTOLOGMNRT 2005-09-21 PROCEDURE INVALID

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=56)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=56)
2 1 BITMAP CONVERSION (TO ROWIDS)
3 2 BITMAP AND
4 3 BITMAP INDEX (SINGLE VALUE) OF 'IND_B_T_STATUS'
5 3 BITMAP INDEX (SINGLE VALUE) OF 'IND_B_T_TYPE'

统计信息
----------------------------------------------------------
29 recursive calls
0 db block gets
56 consistent gets
0 physical reads
0 redo size
611 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
2 rows processed

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'SYS') > 0
2 AND STATUS = 'VALID'
3 AND TYPE = 'PROCEDURE';

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
25701 SYSTEM ORA$_SYS_REP_AUTH 2005-09-21 PROCEDURE VALID
25894 OUTLN ORA$GRANT_SYS_SELECT 2005-09-21 PROCEDURE VALID
.
.
.
10294 SYS XMLVALIDATE 2005-09-21 PROCEDURE VALID

已选择26 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=13 Card=27 Bytes=1512)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=13 Card=27 Bytes=1512)
2 1 BITMAP CONVERSION (TO ROWIDS)
3 2 BITMAP INDEX (SINGLE VALUE) OF 'IND_B_T_TYPE'

统计信息
----------------------------------------------------------
60 recursive calls
0 db block gets
124 consistent gets
0 physical reads
0 redo size
1483 bytes sent via SQL*Net to client
375 bytes received via SQL*Net from client
3 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
26 rows processed

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'TEST') > 0
2 AND STATUS = 'VALID'
3 AND TYPE = 'TABLE';

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
29513 NDMAIN MLOG$_TEST_CAT_ORG 2005-10-15 TABLE VALID
29514 NDMAIN MLOG$_TEST_CAT_ORG2 2005-10-15 TABLE VALID
.
.
.
31309 TEST TT2 2006-08-02 TABLE VALID

已选择49 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=24 Card=5 Bytes=280)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=24 Card=5 Bytes=280)
2 1 BITMAP CONVERSION (TO ROWIDS)
3 2 BITMAP AND
4 3 BITMAP INDEX (SINGLE VALUE) OF 'IND_B_T_TYPE'
5 3 BITMAP CONVERSION (FROM ROWIDS)
6 5 SORT (ORDER BY)
7 6 DOMAIN INDEX OF 'IND_T_NAME' (Cost=19)

统计信息
----------------------------------------------------------
19 recursive calls
0 db block gets
59 consistent gets
0 physical reads
0 redo size
2822 bytes sent via SQL*Net to client
397 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
49 rows processed

上面的3 个查询只有输入的值有所差别,但是Oracle 选择了3 种不同的执行计划,而且从执行效果上看,这些选择都是正确的。

SQL> SELECT COUNT(*) FROM T WHERE CONTAINS(NAME, 'TEST') > 0
2 AND STATUS = 'VALID'
3 AND TYPE = 'TABLE';

COUNT(*)
----------
49

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=24 Card=1 Bytes=53)
1 0 SORT (AGGREGATE)
2 1 BITMAP CONVERSION (COUNT)
3 2 BITMAP AND
4 3 BITMAP INDEX (SINGLE VALUE) OF 'IND_B_T_TYPE'
5 3 BITMAP INDEX (SINGLE VALUE) OF 'IND_B_T_STATUS'
6 3 BITMAP CONVERSION (FROM ROWIDS)
7 6 SORT (ORDER BY)
8 7 DOMAIN INDEX OF 'IND_T_NAME' (Cost=19)

统计信息
----------------------------------------------------------
79 recursive calls
0 db block gets
294 consistent gets
0 physical reads
0 redo size
303 bytes sent via SQL*Net to client
364 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
1 sorts (memory)
0 sorts (disk)
1 rows processed

上面没有改变查询的值,而是将‘* ’换成了‘COUNT(*) ’,那么Oracle 会尝试将域索引转化为BITMAP 索引,然后对所有的BITMAP 索引进行AND 操作,来避免表的访问。

上面是添加了直方图后,全文索引与BITMAP 索引配合使用情况。对于BTREE 索引来说,效果是类似的。

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'TEST') > 0 AND CREATED >= TO_DATE('2006-1-1');

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
30128 NDMAIN TEST 2006-02-23 INDEX VALID
31255 TEST ARTICLES_TAB 2006-11-09 TABLE VALID
.
.
.
31309 TEST TT2 2006-08-02 TABLE VALID

已选择56 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=27 Card=1 Bytes=56)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=27 Card=1 Bytes=56)
2 1 BITMAP CONVERSION (TO ROWIDS)
3 2 BITMAP AND
4 3 BITMAP CONVERSION (FROM ROWIDS)
5 4 SORT (ORDER BY)
6 5 INDEX (RANGE SCAN) OF 'IND_T_CREATED' (NON-UNIQUE) (Cost=2)
7 3 BITMAP CONVERSION (FROM ROWIDS)
8 7 SORT (ORDER BY)
9 8 DOMAIN INDEX OF 'IND_T_NAME' (Cost=19)

统计信息
----------------------------------------------------------
19 recursive calls
0 db block gets
56 consistent gets
0 physical reads
0 redo size
2977 bytes sent via SQL*Net to client
397 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
2 sorts (memory)
0 sorts (disk)
56 rows processed

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'TEST') > 0 AND CREATED >= TO_DATE('2006-11-1');

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
31255 TEST ARTICLES_TAB 2006-11-09 TABLE VALID
.
.
.
31305 TEST T 2006-11-14 TABLE VALID

已选择49 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=24 Card=1 Bytes=56)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=24 Card=1 Bytes=56)
2 1 INDEX (RANGE SCAN) OF 'IND_T_CREATED' (NON-UNIQUE) (Cost=2 Card=70)

统计信息
----------------------------------------------------------
59 recursive calls
0 db block gets
119 consistent gets
0 physical reads
0 redo size
2675 bytes sent via SQL*Net to client
397 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
49 rows processed

SQL> SELECT * FROM T WHERE CONTAINS(NAME, 'TEST') > 0 AND CREATED >= TO_DATE('2005-1-1');

ID NAME CREATED TYPE STATUS
---------- ------------------------------ ---------- ------------------ -------
31309 TEST TT2 2006-08-02 TABLE VALID
31308 TEST TT 2006-08-02 TABLE VALID
.
.
.
6720 SYS DBMS_JAVA_TEST 2005-09-21 PACKAGE VALID

已选择118 行。

执行计划
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=44 Card=118 Bytes=6608)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=44 Card=118 Bytes=6608)
2 1 DOMAIN INDEX OF 'IND_T_NAME' (Cost=19)

统计信息
----------------------------------------------------------
19 recursive calls
0 db block gets
67 consistent gets
0 physical reads
0 redo size
6124 bytes sent via SQL*Net to client
441 bytes received via SQL*Net from client
9 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
118 rows processed

从上面的一系列测试可以发现,如果在表和索引的统计信息的基础上,添加列的直方图,将更加有助于Oracle 选择最有的执行计划。

根据测试,在大部分的情况下,只要收集了正确的统计信息,Oracle 会字段的选择合适的执行计划,全文索引导致执行计划的改变并不会降低系统的性能。

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值