我有一个表(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$
的全表扫描
答案 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自己的固定表的查询性能会更好。