我有一个像这样创建的表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:两个查询都相同。
从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。
答案 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')