sql – 为什么没有索引用于此查询?

前端之家收集整理的这篇文章主要介绍了sql – 为什么没有索引用于此查询?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个查询,当我认为可能是索引没有被使用,所以我好奇地转载了它:

创建一个具有1.000.000行(col中的10个不同值,some_data中的500字节数据)的test_table.

CREATE TABLE test_table AS (
  SELECT MOD(ROWNUM,10) col,LPAD('x',500,'x') some_data
  FROM dual
  CONNECT BY ROWNUM <= 1000000
);

创建索引并收集表统计信息:

CREATE INDEX test_index ON test_table ( col );

EXEC dbms_stats.gather_table_stats( 'MY_SCHEMA','TEST_TABLE' );

尝试获取col和COUNT的不同值:

EXPLAIN PLAN FOR
  SELECT col,COUNT(*)
  FROM test_table
  GROUP BY col;

---------------------------------------------------------------------------------
| Id  | Operation          | Name       | Rows  | Bytes | Cost (%cpu)| Time
---------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |            |    10 |    30 | 15816   (1)| 00:03:10 
|   1 |  HASH GROUP BY     |            |    10 |    30 | 15816   (1)| 00:03:10 
|   2 |   TABLE ACCESS FULL| TEST_TABLE |   994K|  2914K| 15755   (1)| 00:03:10 
---------------------------------------------------------------------------------

该索引未被使用,提供的提示不会改变这一点.

我猜这个索引在这种情况下是不能使用的,但为什么呢?

解决方法

我跑了彼得的原始的东西,并转载他的结果.然后我应用了dcp的建议…
sql> alter table test_table modify col not null;

Table altered.

sql> EXEC dbms_stats.gather_table_stats( user,'TEST_TABLE',cascade=>true)

PL/sql procedure successfully completed.

sql> EXPLAIN PLAN FOR
  2    SELECT col,COUNT(*)
  3    FROM test_table
  4    GROUP BY col;

Explained.

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

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------
Plan hash value: 2099921975

------------------------------------------------------------------------------------
| Id  | Operation             | Name       | Rows  | Bytes | Cost (%cpu)| Time     |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |            |    10 |    30 |   574   (9)| 00:00:07 |
|   1 |  HASH GROUP BY        |            |    10 |    30 |   574   (9)| 00:00:07 |
|   2 |   INDEX FAST FULL SCAN| TEST_INDEX |  1000K|  2929K|   532   (2)| 00:00:07 |
------------------------------------------------------------------------------------

9 rows selected.

sql>

原因很重要,因为NULL值不包含在正常的B-TREE索引中,而GROUP BY必须在查询中包含NULL作为分组“值”.通过告诉优化器在col中没有NULL可以自由使用更高效的索引(FTS使用了近3.55秒的时间).这是一个经典的例子,说明元数据如何影响优化器.

顺便说一下,这显然是10g或11g数据库,因为它使用HASH GROUP BY算法,而不是旧的SORT(GROUP BY)算法.

猜你在找的MsSQL相关文章