Oracle Date索引很慢。没有它,查询速度要快300倍 [英] Oracle Date index is slow. Query is 300 times faster without it

查看:3679
本文介绍了Oracle Date索引很慢。没有它,查询速度要快300倍的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Oracle查询,运行时间为10分钟或更长时间:

I had an Oracle query as below that took 10 minutes or longer to run:

  select
      r.range_text as duration_range,
      nvl(count(c.call_duration),0) as calls,
      nvl(SUM(call_duration),0) as total_duration
      from
      call_duration_ranges r
      left join
      big_table c
      on c.call_duration BETWEEN r.range_lbound AND r.range_ubound
 and c.aaep_src = 'MAIN_SOURCE'
 and c.calltimestamp_local  >= to_date('01-02-2014 00:00:00' ,'dd-MM-yyyy HH24:mi:ss')
 AND c.calltimestamp_local <=  to_date('28-02-2014 23:59:59','dd-MM-yyyy HH24:mi:ss')
 and          c.destinationnumber LIKE substr( 'abc:1301@company.com:5060;user=phone',1,8) || '%'    
 group by
      r.range_text
 order by
      r.range_text

如果我将查询的日期部分更改为:

If I changed the date part of the query to:

 (c.calltimestamp_local+0)  >= to_date('01-02-2014 00:00:00' ,'dd-MM-yyyy HH24:mi:ss')
 (AND c.calltimestamp_local+0) <=  to_date('28-02-2014 23:59:59','dd-MM-yyyy HH24:mi:ss')

它在2秒内运行。我基于另一篇文章做了这个,以避免使用日期索引。虽然看起来很直观 - 索引使事情变得如此之慢。

It runs in 2 seconds. I did this based on another post to avoid using the date index. Seems counter intuitive though--the index slowing things down so much.

完成解释计划,新查询和更新查询之间似乎相同。唯一的区别是MERGE JOIN操作在旧查询中是16,269字节,在新查询中是1,218字节。实际上,旧查询中的基数也更高。而且我实际上没有在解释计划中看到旧的或新查询的INDEX操作,只是针对destinationnumber字段上的索引。

Ran the explain plan and it seems identical between the new and updated query. Only difference is the the MERGE JOIN operation is 16,269 bytes in the old query and 1,218 bytes in the new query. Actually cardinality is higher in the old query as well. And I actually don't see an "INDEX" operation on the old or new query in the explain plan, just for the index on the destinationnumber field.

那么为什么是索引如此放慢了查询速度?我可以对索引做些什么 - 不要认为使用+0是未来的最佳解决方案...

So why is the index slowing down the query so much? What can I do to the index--don't think using the "+0" is the best solution going forward...

查询两天的数据,禁止使用destinationnumber索引:

Querying for two days of data, suppressing use of destinationnumber index:

0   SELECT STATEMENT            ALL_ROWS    329382  1218    14
1   SORT    GROUP BY            329382  1218    14
2   MERGE JOIN  OUTER           329381  1218    14
3   SORT    JOIN            4   308 14
4   TABLE ACCESS    FULL    CALL_DURATION_RANGES    ANALYZED    3   308 14
5   FILTER                      
6   SORT    JOIN            329377  65  1
7   TABLE ACCESS    BY GLOBAL INDEX ROWID   BIG_TABLE   ANALYZED    329376  65  1
8   INDEX   RANGE SCAN  IDX_CDR_CALLTIMESTAMP_LOCAL ANALYZED    1104        342104

使用destinationnumber索引查询2天:

Querying for 2 days using destinationnumber index:

0   SELECT STATEMENT            ALL_ROWS    11  1218    14
1   SORT    GROUP BY            11  1218    14
2   MERGE JOIN  OUTER           10  1218    14
3   SORT    JOIN            4   308 14
4   TABLE ACCESS    FULL    CALL_DURATION_RANGES    ANALYZED    3   308 14
5   FILTER                      
6   SORT    JOIN            6   65  1
7   TABLE ACCESS    BY GLOBAL INDEX ROWID   BIG_TABLE   ANALYZED    5   65  1
8   INDEX   RANGE SCAN  IDX_DESTINATIONNUMBER_PART  ANALYZED    4       4

查询一个月,抑制destinationnumber索引 - 完全扫描:

Querying for one month, suppressing destinationnumber index--full scan:

0   SELECT STATEMENT            ALL_ROWS    824174  1218    14
1   SORT    GROUP BY            824174  1218    14
2   MERGE JOIN  OUTER           824173  1218    14
3   SORT    JOIN            4   308 14
4   TABLE ACCESS    FULL    CALL_DURATION_RANGES    ANALYZED    3   308 14
5   FILTER                      
6   SORT    JOIN            824169  65  1
7   PARTITION RANGE ALL         824168  65  1
8   TABLE ACCESS    FULL    BIG_TABLE   ANALYZED    824168  65  1


推荐答案


似乎反直觉 - 索引减慢了很多东西。

Seems counter intuitive though--the index slowing things down so much.

只有在你不理解时才会有直觉索引如何工作。

Counter-intuitive only if you don't understand how indexes work.

索引适用于检索单个行。它们不适合检索大量记录。您没有费心提供任何指标,但您的查询似乎可能触及大量行。在这种情况下,全表扫描或其他基于set =的操作将更有效。

Indexes are good for retrieving individual rows. They are not suited to retrieving large numbers of records. You haven't bothered to provide any metrics but it seems likely your query is touching a large number of rows. In which case a full table scan or other set=based operation will be more much efficient.

调整日期范围查询是棘手,因为无论我们的统计数据是多么最新,数据库都很难知道两个边界之间有多少记录。 (当日期界限可能变化时调整甚至更棘手 - 一天与一个月或一年不同。)因此,我们经常需要通过使用我们对数据的了解来帮助优化器。

Tuning date range queries is tricky, because it's very hard for the database to know how many records lie between the two bounds, no matter how up-to-date our statistics are. (Even more tricky to tune when the date bounds can vary - one day is a different matter from one month or one year.) So often we need to help the optimizer by using our knowledge of our data.


不要认为使用+0是未来的最佳解决方案......

don't think using the "+0" is the best solution going forward...

为什么不呢?人们一直在使用该技术来避免在几十年内在特定查询中使用索引。

Why not? People have been using that technique to avoid using an index in a specific query for literally decades.

然而,还有更多现代化的解决方案。未记录的基数提示是一个:

However, there are more modern solutions. The undocumented cardinality hint is one:

 select /*+ cardinality(big_table,10000) */ 

...应足以阻止优化器使用索引 - 只要您为 all收集了准确的统计信息查询中的表。

... should be enough to dissuade the optimizer from using an index - provided you have accurate statistics gathered for all the tables in the query.

或者你可以强制优化器用...进行全表扫描。

Alternatively you can force the optimizer to do a full table scan with ...

 select /*+ full(big_table) */ 

无论如何,你什么都没有做索引来改变数据库的工作方式。你可以通过分区来加快速度,但我想如果你的组织已经购买了分区选项您已经在使用它了。

Anyway, there's nothing you can do to the index to change the way databases work. You could make things faster with partitioning, but I would guess if your organisation had bought the Partitioning option you'd be using it already.

这篇关于Oracle Date索引很慢。没有它,查询速度要快300倍的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆