为啥查询不使用Oracle中的索引

Posted

技术标签:

【中文标题】为啥查询不使用Oracle中的索引【英文标题】:Why is query not using index in Oracle为什么查询不使用Oracle中的索引 【发布时间】:2014-05-11 23:17:21 【问题描述】:

如果我查询 1、2、3、4 或 5 天的数据,我有一个使用日期索引的查询。对于这些查询,数据会在 10 秒内返回。对于 6 天或更长时间,它决定不使用索引,并且查询需要永远,如果它完全返回的话。如果我尝试使用索引帮助,它似乎没有使用索引。我尝试对索引和表进行收集统计。这是查询(本例中为 9 天的数据):

select 

                        r.range_text as duration_range,
                        nvl(count(c.call_duration),0) as calls,
                        nvl(SUM(call_duration),0) as total_duration
                    from
                        duration_ranges r
                    left join
                        big_table c
                    on c.call_duration >= r.range_lbound AND c.call_duration <= r.range_ubound

                    where calltimestamp_local >= to_date('20-02-2014 00:00:00','dd-MM-yyyy HH24:mi:ss')
                    and calltimestamp_local <= to_date('28-02-2014 23:59:59' ,'dd-MM-yyyy HH24:mi:ss')
                     and  c.destinationnumber = 'sip:1000@company.com:5060;user=phone'
                    group by
                    r.range_text
                order by
                    r.range_text;  

这里是没有索引的解释计划:

Without Index
SELECT STATEMENT  ALL_ROWSCost: 827,605  Bytes: 1,344  Cardinality: 14                          
    8 SORT GROUP BY  Cost: 827,605  Bytes: 1,344  Cardinality: 14                   
        7 MERGE JOIN  Cost: 827,486  Bytes: 246,552,768  Cardinality: 2,568,258                 
            2 SORT JOIN  Cost: 4  Bytes: 308  Cardinality: 14           
                1 TABLE ACCESS FULL TABLE MYDB.DURATION_RANGES Cost: 3  Bytes: 308  Cardinality: 14         
            6 FILTER            
                5 SORT JOIN  Cost: 827,471  Bytes: 14,164,118  Cardinality: 191,407         
                    4 PARTITION RANGE ALL  Cost: 824,134  Bytes: 14,164,118  Cardinality: 191,407  Partition #: 7  Partitions accessed #1 - #1653   
                        3 TABLE ACCESS FULL TABLE MYDB.BIG_TABLE Cost: 824,134  Bytes: 14,164,118  Cardinality: 191,407  Partition #: 7  Partitions accessed #1 - #1653

带索引:

With Index
Plan
SELECT STATEMENT  ALL_ROWSCost: 822,732  Bytes: 1,344  Cardinality: 14                          
    8 SORT GROUP BY  Cost: 822,732  Bytes: 1,344  Cardinality: 14                   
        7 MERGE JOIN  Cost: 822,635  Bytes: 205,460,736  Cardinality: 2,140,216                 
            2 SORT JOIN  Cost: 4  Bytes: 308  Cardinality: 14           
                1 TABLE ACCESS FULL TABLE MYDB.DURATION_RANGES Cost: 3  Bytes: 308  Cardinality: 14         
            6 FILTER            
                5 SORT JOIN  Cost: 822,621  Bytes: 11,803,444  Cardinality: 159,506         
                    4 TABLE ACCESS BY GLOBAL INDEX ROWID TABLE MYDB.BIG_TABLE Cost: 819,841  Bytes: 11,803,444  Cardinality: 159,506  Partition #: 7  Partition access computed by row location 
                        3 INDEX RANGE SCAN INDEX MYDB.IDX_CDR_CALLTIMESTAMP_LOCAL Cost: 2,744  Cardinality: 850,691  

知道如果 5 天的数据恢复得非常快,它为什么不使用索引?它似乎并没有优化事物,因为它返回的速度要慢得多。

【问题讨论】:

顺便说一句,版本是 Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production 【参考方案1】:

也许因为数据和索引不会发生太大变化,它的工作速度会变慢?您可以通过强制 Oracle 使用索引来轻松检查它 - 指定 INDEX 提示,然后将时间与索引进行比较,没有它的相同查询。

您还可以指定 NOINDEX 提示来比较 5 天或更少天的时间。

【讨论】:

我尝试了索引提示,但似乎没有用。应该是这样的吧? (其中 IDX_CDR_CALLTIMESTAMP_LOCAL 是索引名称)select /*+ index(big_table IDX_CDR_CALLTIMESTAMP_LOCAL) */ r.range_text as duration_range, nvl(count(c.call_duration),0) as calls, nvl(SUM(call_duration),0) as total_duration from .... etc. @user2281976 如果您使用表的别名,那么您可能也应该在提示中使用它:select /*+ index(c IDX_CDR_CALLTIMESTAMP_LOCAL) */ ... 我以为我试过了——我猜我没有。是的,必须使用别名。对于 6 天的数据,如果我强制使用索引,它会更好地恢复,但它仍然比 5 天慢得多。回顾一下,如果我在选择中选择 1-5 天,则只需不到 10 秒,6 天(强制使用索引)不到 2 分钟。如果我在没有日期索引的情况下尝试 6 天的数据,它会运行很长时间。 我应该说事实证明我没有在桌面上收集统计数据 - 与其他人一起工作,他们错误地说他们做了。一定是统计问题——但我想知道为什么查询时间在 5 到 6 天之间会有这样的跳跃——在那额外的一天里没有更多的数据......

以上是关于为啥查询不使用Oracle中的索引的主要内容,如果未能解决你的问题,请参考以下文章

为啥 oracle 对此查询使用索引跳过扫描?

在Oracle中定义SQL查询。索引为啥不能直接从select语句中引用?求教,谢谢

oracle 数据索引为啥没有起到作用

为啥 Oracle 在应该使用索引时使用全表扫描?

为啥 MySQL 中的这个查询不使用索引?

oracle 唯一约束 为啥 唯一索引