Oracle 如何获得计数(col)。。。分组方式以使用索引?

Oracle 如何获得计数(col)。。。分组方式以使用索引?,oracle,group-by,indexing,query-optimization,Oracle,Group By,Indexing,Query Optimization,我有一张桌子col1,col2。。。在col1,col2。。。。表中有数百万行,我想运行一个查询: SELECT col1, COUNT(col2) WHERE col1 NOT IN (<couple of exclusions>) GROUP BY col1 SYS.OBJ$SYS.I_OBJ2上有一个索引,它对owner和name列进行索引;我相信我应该能够在查询中使用此索引,而不是对SYS.OBJ$进行完整的表扫描, 但请记住,使用索引可能并不总是导致更快的执行 以防万一

我有一张桌子col1,col2。。。在col1,col2。。。。表中有数百万行,我想运行一个查询:

 SELECT col1, COUNT(col2) WHERE col1 NOT IN (<couple of exclusions>) GROUP BY col1
SYS.OBJ$SYS.I_OBJ2上有一个索引,它对owner和name列进行索引;我相信我应该能够在查询中使用此索引,而不是对SYS.OBJ$进行完整的表扫描,
但请记住,使用索引可能并不总是导致更快的执行

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


当然,如果这适合您的问题,请尝试使用COUNT*而不是COUNTcol2。另外,也许可以尝试只使用col1的索引。

我曾经有机会尝试过这一点,而我之前关于NOT IN的评论在这种情况下是一种误导。关键是是否存在空值,或者更确切地说,索引列是否没有强制执行空约束

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

如果没有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>

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

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

删除NOT IN STALL会导致对表进行完整的表扫描,查询计划中的表访问权限已满,成本为2200。我不能在上面创建索引,但是col1,col2。。。对于针对col1的查询,是否与col1上的索引相同?
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>
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>