索引范围扫描 vs 索引跳过扫描 vs 索引快速全扫描

Posted

技术标签:

【中文标题】索引范围扫描 vs 索引跳过扫描 vs 索引快速全扫描【英文标题】:Index range scan vs index skip scan vs index fast full scan 【发布时间】:2013-09-27 20:21:46 【问题描述】:

我有桌子

test_A(
    id1 number,
    id2 number,
    id3 number,
    name varchar2(10),
    create_dt date
)

我在(id1,id2)indx2(id3) 上有两个索引一个复合索引indx1。现在当我查询这张表时test_A as

select * from test_A where id2=123 and 
create_dt=(select max(create_dt) from test_A where test_A.id2=id2);

我为上面的 SQL 运行了解释计划,它使用“索引跳过扫描”。如果我在create_dt 上创建另一个索引,那么它使用索引快速全扫描和所有成本,%cpu 显示高于使用索引跳过扫描的计划。它还在create_dt 上创建索引后使用索引范围扫描。

我无法得出哪个应该可以的结论?我需要在create_dt 上创建另一个索引还是索引跳过扫描好?我相信索引跳过是 Oracle 运行多个索引范围扫描的功能?

【问题讨论】:

【参考方案1】:

我建议您熟悉此链接:http://docs.oracle.com/cd/E16655_01/server.121/e15858/tgsql_optop.htm#CHDFJIJA 它与 Oracle 12c 相关,但了解 Oracle 如何在所有 DBMS 版本中使用不同的索引访问路径非常有用。 您的子查询不明确:

select max(create_dt) from test_A where test_A.id2=id2

test_A.id2和id2都引用同一个test_A.id2,查询等价于:

select * from test_A where id2=123 and 
create_dt=(select max(create_dt) from test_A where id2=id2);

或者简单地说:

select * from test_A where id2=123 and 
create_dt=(select max(create_dt) from test_A where id2 is not null);

我想你想要这样的东西:

select * from test_A where id2=123 and 
create_dt=(select max(create_dt) 
           from test_A ALIAS 
           where test_A.id2=ALIAS.id2);

对于上面的查询,id2+create_dt 上的复合索引最有可能给出最好的结果,试试吧:

CREATE INDEX index_name ON test_A( id2, create_dt);

【讨论】:

感谢上述解决方案。我在这 2 列的索引中创建了复合索引,从而降低了解释计划的成本。我还有一个问题,假设我在 (id1,id2) 上的另一个表上创建了唯一约束,我们需要在外部创建索引还是唯一约束处理索引。我在很多论坛上都读过这个,有人说它会照顾 Index 一些人需要创建 Index ,不能就此得出结论。如果您对此有任何信息,请告诉我。 自己试试吧。请参阅此链接:sqlfiddle.com/#!2/180be/1 那里有三个缩进表,第一个没有索引,第二个使用create index 创建的索引,第三个在表定义中使用constraint .. unique。运行附加查询,然后单击View execution plan 链接并比较个人解释计划,看看其中哪些使用了索引。

以上是关于索引范围扫描 vs 索引跳过扫描 vs 索引快速全扫描的主要内容,如果未能解决你的问题,请参考以下文章

SQL Tuning 基础概述10

Mysql之索引优化

MySQL索引失效原因

explain(desc)命令的使用

索引为何不可用

sql优化