优化器始终完全扫描表eben虽然只有3行

时间:2017-04-02 15:16:24

标签: oracle performance database-performance

我有一个像这样创建的表foo。

CREATE TABLE foo AS SELECT * FROM all_objects;

CREATE INDEX foo_I1 ON foo(owner,object_type,status);
exec dbms_stats.gather_table_stats('hr','foo',method_opt=>'FOR ALL COLUMNS size AUTO');

我在3列上创建了一个索引并触发了一个如下所示的查询。

select  * from foo where status='INVALID';
select  * from foo where status='VALID';

状态=' VALID'在71780行的表中提取大约71000行。它进行全表扫描。这是可以理解的。但如果状态='无效'它只获取3行,它正在进行全表扫描。它也使A行和E行非常不同。

PLAN:两个查询都相同。

SQL_ID gdhy9j91gu9sm,子编号0

从foo中选择/ * + gather_plan_statistics * / *,其中status =' VALID'

Plan hash value: 1245013993

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     50 |00:00:00.01 |       4 |
|*  1 |  TABLE ACCESS FULL| FOO  |      1 |  71773 |     50 |00:00:00.01 |       4 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("STATUS"='VALID')

请解释此行为。数据库版本:11.2g oracle。

1 个答案:

答案 0 :(得分:1)

缺少的直方图可能导致全表扫描。直方图通常仅在数据偏斜时创建,如果该列已在相关谓词中使用。

有时您需要在收集统计信息之前运行查询,让Oracle知道此列非常重要,足以获得直方图。

select * from foo where status='INVALID';
exec dbms_stats.gather_table_stats('hr','foo',method_opt=>'FOR ALL COLUMNS size AUTO');

重新运行SELECT,现在可以使用直方图。使用直方图,Oracle知道INVALID返回少量行,并且索引很有用:

explain plan for select * from foo where status='INVALID';
select * from table(dbms_xplan.display);

Plan hash value: 1520589999

---------------------------------------------------------------------------------------------
| Id  | Operation                           | Name   | Rows  | Bytes | Cost (%CPU)| Time    |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                    |        |     1 |   134 |   217   (0)| 00:00:01|
|   1 |  TABLE ACCESS BY INDEX ROWID BATCHED| FOO    |     1 |   134 |   217   (0)| 00:00:01|
|*  2 |   INDEX SKIP SCAN                   | FOO_I1 |     1 |       |   216   (0)| 00:00:01|
---------------------------------------------------------------------------------------------


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("STATUS"='INVALID')
       filter("STATUS"='INVALID')