【HINT】使用“NO_INDEX ”Hint提示避免SQL使用特定索引

secooler發表於2011-05-04
  在生產環境的SQL調優測試過程中經常遇到如下場景:一張表上建立了非常多的索引(不推薦),每一個索引都是針對特定業務查詢而增加的。這極易導致SQL由於個別索引的引入出現效能問題,在這種情況下不能簡簡單單的將索引刪除在解決問題。如何避免SQL不使用特定索引這個問題便擺在了我們面前。

  這裡給出通過使用Hint的方法實現強制SQL不走特定索引的方法。

  在眾多Oracle Hint中我們選中了“NO_INDEX”。

1.環境準備
1)建立表T
sec@ora10g> create table t as select * from all_objects;

Table created.

sec@ora10g> select count(*) from t;

  COUNT(*)
----------
     11139

2)在object_name列上建立索引t_idx1
sec@ora10g> create index t_idx1 on t(object_name);

Index created.

3)在object_id列上建立索引t_idx2
sec@ora10g> create index t_idx2 on t(object_id);

Index created.

2.未使用“NO_INDEX”提示時索引使用情況
sec@ora10g> set autotrace on
sec@ora10g> select object_name from t where object_name = 'T';

OBJECT_NAME
------------------------------
T


Execution Plan
----------------------------------------------------------
Plan hash value: 3419373504

---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |     1 |    17 |     1   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| T_IDX1 |     1 |    17 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------
……省略其他資訊輸出……


sec@ora10g> select object_name from t where object_id = 11915;

OBJECT_NAME
------------------------------
T


Execution Plan
----------------------------------------------------------
Plan hash value: 3371054274

--------------------------------------------------------------------------------------
| Id  | Operation                   | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |        |     1 |    30 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T      |     1 |    30 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | T_IDX2 |     1 |       |     1   (0)| 00:00:01 |
--------------------------------------------------------------------------------------
……省略其他資訊輸出……


可見以上兩條SQL語句均能正常使用到索引。

3.使用“NO_INDEX”提示時索引使用情況
sec@ora10g> select /*+ NO_INDEX(t t_idx1) */ object_name from t where object_name = 'T';

OBJECT_NAME
------------------------------
T


Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     2 |    34 |    35   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     2 |    34 |    35   (0)| 00:00:01 |
--------------------------------------------------------------------------
……省略其他資訊輸出……


sec@ora10g> select /*+ NO_INDEX(t t_idx2) */ object_name from t where object_id = 11915;

OBJECT_NAME
------------------------------
T


Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     2 |    60 |    35   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     2 |    60 |    35   (0)| 00:00:01 |
--------------------------------------------------------------------------
……省略其他資訊輸出……


此處均顯示為使用到對應的索引進行檢索資料。我們的實驗目標已經實現。

4.“NO_INDEX”提示的用法補充說明
1)Oracle 10g官方文件中關於no_index這個HINT的描述資訊參見如下連結
http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/sql_elements006.htm#SQLRF50411

NO_INDEX Hint

De.ion of no_index_hint.gif follows
Description of the illustration no_index_hint.gif

(See "Specifying a Query Block in a Hint", tablespec::=, indexspec::=)

The NO_INDEX hint instructs the optimizer not to use one or more indexes for the specified table. For example:

SELECT /*+ NO_INDEX(employees emp_empid) */ employee_id 
FROM employees
WHERE employee_id > 200;

Each parameter serves the same purpose as in "INDEX Hint" with the following modifications:

  • If this hint specifies a single available index, then the optimizer does not consider a scan on this index. Other indexes not specified are still considered.

  • If this hint specifies a list of available indexes, then the optimizer does not consider a scan on any of the specified indexes. Other indexes not specified in the list are still considered.

  • If this hint specifies no indexes, then the optimizer does not consider a scan on any index on the table. This behavior. is the same as a NO_INDEX hint that specifies a list of all available indexes for the table.

The NO_INDEX hint applies to function-based, B-tree, bitmap, cluster, or domain indexes. If a NO_INDEX hint and an index hint (INDEX, INDEX_ASC, INDEX_DESC, INDEX_COMBINE, or INDEX_FFS) both specify the same indexes, then the database ignores both the NO_INDEX hint and the index hint for the specified indexes and considers those indexes for use during execution of the statement.


2)在一條SQL中可以給出多個索引名稱,以便在執行SQL時避免使用這些索引。
sec@ora10g> select /*+ NO_INDEX(t t_idx2 t_idx1) */ object_name from t where object_id = 11915;

OBJECT_NAME
------------------------------
T


Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     2 |    60 |    35   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     2 |    60 |    35   (0)| 00:00:01 |
--------------------------------------------------------------------------
……省略其他資訊輸出……


3)當任何索引都不列出的情況下表示T表上的所有索引都不被使用!
sec@ora10g> select /*+ NO_INDEX (t) */ object_name from t where object_id = 11915;

OBJECT_NAME
------------------------------
T


Execution Plan
----------------------------------------------------------
Plan hash value: 1601196873

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     2 |    60 |    35   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T    |     2 |    60 |    35   (0)| 00:00:01 |
--------------------------------------------------------------------------
……省略其他資訊輸出……


5.小結
  在SQL優化中使用Hint提示的方法往往是萬不得已而為止的行為。不過本文中提到的方法也可以用於SQL語句的除錯和故障排除。靈活使用之。

Good luck.

secooler
11.05.04

-- The End --

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/519536/viewspace-694457/,如需轉載,請註明出處,否則將追究法律責任。

相關文章