如何获得COUNT(col)... GROUP BY来使用索引?

时间:2010-04-29 11:32:14

标签: oracle group-by indexing query-optimization

我有一个表(col1,col2,...),索引为(col1,col2,...)。该表中有数百万行,我想运行一个查询:

 SELECT col1, COUNT(col2) WHERE col1 NOT IN (<couple of exclusions>) GROUP BY col1

不幸的是,这导致了对表的全表扫描,这需要花费一分钟。有没有办法让oracle使用列上的索引来更快地返回结果?

修改

更具体地说,我正在运行以下查询:

SELECT owner, COUNT(object_name) FROM all_objects GROUP BY owner

并且SYS.OBJ$SYS.I_OBJ2)上有一个索引,用于索引owner#name列;我相信我应该能够在查询中使用此索引,而不是SYS.OBJ$的全表扫描

4 个答案:

答案 0 :(得分:3)

我有机会玩这个,我之前关于NOT IN的评论在这种情况下是红鲱鱼。关键是存在NULL,或者说索引列是否强制执行NOT NULL约束。

这将取决于您正在使用的数据库的版本,因为优化程序会在每个版本中变得更智能。我正在使用11gR1并且优化器在所有情况下都使用了索引,除了一个:当两个列都为null并且我没有包含NOT IN子句时:

SQL> desc big_table
 Name                                  Null?    Type
 -----------------------------------  ------    -------------------
 ID                                             NUMBER
 COL1                                           NUMBER
 COL2                                           VARCHAR2(30 CHAR)
 COL3                                           DATE
 COL4                                           NUMBER

没有NOT IN子句......

SQL> explain plan for
  2      select col4, count(col1) from big_table
  3      group by col4
  4  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------
Plan hash value: 1753714399

----------------------------------------------------------------------------------------
| Id  | Operation          | Name      | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |           | 31964 |   280K|       |  7574   (2)| 00:01:31 |
|   1 |  HASH GROUP BY     |           | 31964 |   280K|    45M|  7574   (2)| 00:01:31 |
|   2 |   TABLE ACCESS FULL| BIG_TABLE |  2340K|    20M|       |  4284   (1)| 00:00:52 |
----------------------------------------------------------------------------------------

9 rows selected.


SQL>

当我重新执行NOT IN子句时,优化器选择使用索引。怪异。

SQL> explain plan for
  2      select col4, count(col1) from big_table
  3      where col1 not in (12, 19)
  4      group by col4
  5  /

Explained.

SQL> select * from table(dbms_xplan.display)
  2  /

PLAN_TABLE_OUTPUT
---------------------------------------------------------------------------------------
Plan hash value: 343952376

----------------------------------------------------------------------------------------
| Id  | Operation             | Name   | Rows  | Bytes |TempSpc| Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |        | 31964 |   280K|       |  5057   (3)| 00:01:01 |
|   1 |  HASH GROUP BY        |        | 31964 |   280K|    45M|  5057   (3)| 00:01:01 |
|*  2 |   INDEX FAST FULL SCAN| BIG_I2 |  2340K|    20M|       |  1767   (2)| 00:00:22 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------

   2 - filter("COL1"<>12 AND "COL1"<>19)

14 rows selected.

SQL>

重复一遍,在所有其他情况下,只要其中一个索引列被声明为nill,索引就用于满足查询。在早期版本的Oracle上可能不是这样,但它可能指明了前进的方向。

答案 1 :(得分:0)

您可以使用提示http://download.oracle.com/docs/cd/B10501_01/server.920/a96533/hintsref.htm, 但请记住,使用索引可能并不总能导致执行速度更快。

答案 2 :(得分:0)

(以防万一,你确定它正在进行表扫描而不是索引扫描吗?)

尝试使用COUNT(*)代替COUNT(col2)(假设这适合您的问题,当然)。此外,也许只需col1尝试一个索引。

答案 3 :(得分:0)

你正在查询oracle的固定表,因为你没有说明这是哪个db vesion,我会假设最近的一个。是否对固定表进行了分析并更新了统计数据?您是否通过使用/ * +规则* /提示使用规则库优化器尝试了查询。我经常看到,当使用规则库优化器时,针对oracle自己的固定表的查询性能会更好。