为什么oracle会忽略暗示的虚拟索引?

时间:2014-08-05 12:33:18

标签: oracle indexing hint

我试图找出优化查询的最佳方法,所以我创建了一个除了另一个创建的索引之外的虚拟索引,所以现在我有一个包含所有字段的“真实”索引和虚拟索引。当我运行执行计划时,它使用“真正的”,所以我避免使用这样的提示:

select /*+INDEX (VIRTUAL_INDEX) */1,2,3,sum(4) ,5 
  from TABLE 
 group by 1,2,3,5 
HAVING SUM(4)>0

但现在它没有使用任何索引,执行计划显示完整扫描而不是指向新的虚拟索引...... 我真的不太了解提示或虚拟索引,所以也许/可能我做错了什么,但我看不出来,有人可以帮我吗?

感谢。

2 个答案:

答案 0 :(得分:2)

首先,要使优化器使用索引,您必须编写如下的提示:

select /*+INDEX (TABLE1 INDEX_NAME) */ *
  from TABLE1

其次,尝试像这样打开_use_nosegment_indexes参数:

ALTER SESSION SET "_use_nosegment_indexes" = TRUE;

要了解有关虚拟索引的更多信息,请使用this article

如果我是你,我不会浪费我的时间来制作oracle使用索引,如果oracle不使用它,它不需要索引。在解析和分析期间,优化器会评估所有可能的提取行的方法,并选择成本最低的方法。优化程序根据统计信息执行此评估。所以请确保您有新的统计数据。

答案 1 :(得分:1)

提示适用于虚拟索引。这是一个演示,首先是一个真正的索引:

SQL> CREATE TABLE test_table (
  2     ID NUMBER PRIMARY KEY,
  3     small_data NUMBER(2) NOT NULL,
  4     other_data NUMBER(3) NOT NULL,
  5     big_data CHAR(1000));
Table created
SQL> INSERT INTO test_table
  2     (SELECT ROWNUM, MOD(ROWNUM, 10), MOD(ROWNUM, 99), 'x'
  3        FROM dual CONNECT BY LEVEL <= 1000);
1000 rows inserted
SQL> CREATE INDEX test_real_idx ON test_table (small_data, other_data);
Index created
SQL> BEGIN
  2     dbms_stats.gather_table_stats(
  3        USER, 'TEST_TABLE',
  4        method_opt => 'FOR ALL INDEXED COLUMNS SIZE 1',
  5        cascade => TRUE);
  6  END;
  7  /
PL/SQL procedure successfully completed
SQL> EXPLAIN PLAN FOR (SELECT small_data, SUM(other_data)
  2                      FROM test_table
  3                     GROUP BY small_data);
Explained
SQL> SELECT * FROM table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 590429246
--------------------------------------------------------------------------------
| Id  | Operation             | Name          | Rows  | Bytes | Cost (%CPU)| Tim
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |               |    10 |    60 |     3  (34)| 00:
|   1 |  HASH GROUP BY        |               |    10 |    60 |     3  (34)| 00:
|   2 |   INDEX FAST FULL SCAN| TEST_REAL_IDX |  1000 |  6000 |     2   (0)| 00:
--------------------------------------------------------------------------------

然后我们创建一个虚拟的,我们将反转列,因为没有两个索引可以按相同的顺序具有完全相同的列:

SQL> CREATE INDEX test_virtual_idx
  2     ON test_table (other_data, small_data)
  3     NOSEGMENT;
Index created
SQL> ALTER SESSION SET "_use_nosegment_indexes" = TRUE;
Session altered
SQL> EXPLAIN PLAN FOR (
  2     SELECT /*+ INDEX (TEST_TABLE TEST_VIRTUAL_IDX)*/small_data,
  3            SUM(other_data)
  4       FROM test_table
  5      GROUP BY small_data);
Explained
SQL> SELECT * FROM table(dbms_xplan.display);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Plan hash value: 2641322569
--------------------------------------------------------------------------------
| Id  | Operation        | Name             | Rows  | Bytes | Cost (%CPU)| Time
--------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                  |    10 |    60 |    27   (4)| 00:00
|   1 |  HASH GROUP BY   |                  |    10 |    60 |    27   (4)| 00:00
|   2 |   INDEX FULL SCAN| TEST_VIRTUAL_IDX |  1000 |  6000 |    26   (0)| 00:00
--------------------------------------------------------------------------------

正如您所看到的,由于提示,虚拟索引优先于实际索引。

从您的问题看来,真正的索引似乎不再使用了,这可能是这里的主要问题:索引可能不足以回答查询(因为可能是nullable column)。