使用反转索引提高SQL的执行效率 ? 半瓶

来源:百度文库 编辑:神马文学网 时间:2024/04/30 23:49:36

最近优化SQL的执行计划,使用到了反转索引,记录一下。以下是在测试环境中的结果,生产环境建立索引等操作要小心点。先看一个常规的索引:

一般我们先看看这个表的数据量:

SQL> select bytes/1024/1024 from dba_segments whereowner='ERP' and segment_name=upper('invoice');

BYTES/1024/1024
---------------
456

执行SQL查看执行计划:

SQL> set linesize 120
SQL> set autotrace on
SQL> select sbcode from invoice where paicode = '000000995430';

no rows selected

Execution Plan
----------------------------------------------------------
Plan hash value: 2742044924

-----------------------------------------------------------------------------
| Id  | Operation         | Name    | Rows  | Bytes | Cost (%CPU)|Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |         |     1 |     8 | 12980   (2)|00:02:36 |
|*  1 |  TABLE ACCESS FULL| INVOICE |     1 |     8 | 12980   (2)|00:02:36 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("PAICODE"='000000995430')

Statistics
----------------------------------------------------------
1989  recursive calls
0  db block gets
58447  consistent gets
58039  physical reads
0  redo size
323  bytes sent via SQL*Net to client
481  bytes received via SQL*Net from client
1  SQL*Net roundtrips to/from client
49  sorts (memory)
0  sorts (disk)
0  rows processed

很明显走了全表扫描,下面建立索引:

SQL> create index idx_invoice_paicode oninvoice(paicode) tablespace erp_index;

Index created.

然后再看执行计划:

SQL> select sbcode from invoice where paicode ='000000995430';

no rows selected

Execution Plan
----------------------------------------------------------
Plan hash value: 3585586676

---------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name                | Rows  |Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                     |     1 |     8|     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| INVOICE             |     1 |     8|     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_INVOICE_PAICODE |     1|       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access("PAICODE"='000000995430')

Statistics
----------------------------------------------------------
24  recursive calls
0  db block gets
5  consistent gets
1  physical reads
0  redo size
323  bytes sent via SQL*Net to client
481  bytes received via SQL*Net from client
1  SQL*Net roundtrips to/from client
0  sorts (memory)
0  sorts (disk)
0  rows processed

效果不言而喻,除了时间因素,逻辑读和物理读下降都很明显。

下面看一个反转索引的例子,一般查询条件是like '%XXX'的时候我们考虑使用反转索引,先看下数据量:

SQL> select bytes/1024/1024 from dba_segments whereowner='ERP' and segment_name=upper('ratifytask');

BYTES/1024/1024
---------------
4768

执行SQL,查看执行计划:

SQL> select rtask from ratifytask where rtask like'%gtrafsheet.0000000000125193';

RTASK
----------------------------------------------------------------
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193

7 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 3455136816

-----------------------------------------------------------------------------------------
| Id  | Operation            | Name             | Rows  | Bytes | Cost(%CPU)| Time     |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |                  |   202K|  6929K| 5778   (2)| 00:01:10 |
|*  1 |  INDEX FAST FULL SCAN| RATIFYTASK_RTASK |   202K|  6929K| 5778   (2)| 00:01:10 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

1 - filter("RTASK" LIKE '%gtrafsheet.0000000000125193')

Statistics
----------------------------------------------------------
524  recursive calls
0  db block gets
26179  consistent gets
25966  physical reads
0  redo size
831  bytes sent via SQL*Net to client
492  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
10  sorts (memory)
0  sorts (disk)
7  rows processed

建立反转索引:

SQL> create index idx_ratifytask_rtask_reverse onratifytask(reverse(rtask)) tablespace erp_index;

Index created.

然后再查会发现执行计划并没有改变,这是因为我们首先要告诉CBO更新统计信息:

SQL> execdbms_stats.gather_table_stats('erp','RATIFYTASK',cascade=>true);

PL/SQL procedure successfully completed.

这是个费时的操作,生产环境繁忙时段千万别这么干,然后再看执行计划:

SQL> select rtask from ratifytask where reverse(rtask)like reverse('%gtrafsheet.0000000000125193');

RTASK
----------------------------------------------------------------
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193
203041:gtrafsheet.0000000000125193

7 rows selected.

Execution Plan
----------------------------------------------------------
Plan hash value: 1377131512

------------------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name                         |Rows  | Bytes | Cost (%CPU)| Time     |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                              |    7 |   245 |    10   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| RATIFYTASK                   |    7 |   245 |    10   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_RATIFYTASK_RTASK_REVERSE |    7 |       |     3   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

2 - access(REVERSE("RTASK") LIKE '3915210000000000.teehsfartg%')
filter(REVERSE("RTASK") LIKE '3915210000000000.teehsfartg%')

Statistics
----------------------------------------------------------
281  recursive calls
0  db block gets
121  consistent gets
11  physical reads
0  redo size
831  bytes sent via SQL*Net to client
492  bytes received via SQL*Net from client
2  SQL*Net roundtrips to/from client
26  sorts (memory)
0  sorts (disk)
7  rows processed

效果十分明显,达到目的。