加入两个Oracle表,日期到不重叠的日期范围

时间:2012-06-06 08:52:55

标签: sql oracle oracle10g sql-optimization

我有两张桌子:

  • 行程:id_trip,id_object,trip_date,delta(8980026行)
  • 范围:id_range,id_object,date_since,date_until(18490行)

我需要优化以下select语句

  select r.id_range, sum(t.delta) sum_deltas
    from trips t,
         ranges r
   where t.id_object = r.id_object
     and t.trip_date between r.date_since and r.date_until
group by r.id_range

根据条件,在'范围内始终只有一个匹配的旅行行

  • 旅行表不断增长,但没有更新或删除
  • 表格范围可能会不时地以任何方式改变(删除,更新,插入),因此基于函数的索引不是这样的:(
  • id_object(在两个表中)和date_since(在旅行中)都有索引

有没有人知道如何加快速度,甚至可能?

2 个答案:

答案 0 :(得分:1)

您可能希望查看数据分段(即按特定日期对数据进行分区,导致查询仅访问相应的分区)和索引,这些可能会加快查询过程。

此外,您可以考虑使用数据仓库......您说Trips永远不会被更新或删除,因此它是非规范化为更适合报告生成和即席查询的数据结构的理想候选者。

答案 1 :(得分:1)

总是可以加快速度;它可能不值得花时间/精力/金钱/磁盘空间/额外开销等。

首先请使用显式连接语法。几十年来它一直是SQL标准,它有助于避免许多潜在的错误。您的查询将变为:

select r.id_range, sum(t.delta) sum_deltas
  from trips t
  join ranges r
    on t.id_object = r.id_object
   and t.trip_date between r.date_since and r.date_until
 group by r.id_range

此查询意味着您需要两个索引 - 如果可能,则为唯一索引。在ranges上,您应该在id_object, date_since, date_until上有一个索引。 trips上的索引为id_object, trip_date。如果trips较小,我可以考虑将delta添加到该索引的末尾,这样您就不会输入表,只会进行索引扫描。就目前而言,您将不得不通过索引rowid进行表访问。

写完所有问题可能会略有不同。您将使用此查询对这两个表进行全面扫描。您的问题可能是索引。如果优化器正在使用索引,那么您可能正在为id_objecttrips中的每个ranges执行索引唯一/范围扫描,然后,因为使用的列不在您将通过索引rowid对表进行访问的索引。这可能非常昂贵。

尝试添加hint以强制对两个表进行全面扫描:

select /*+ full(t) full(r) */ r.id_range, sum(t.delta) sum_deltas
  from trips t
  join ranges r
    on t.id_object = r.id_object
   and t.trip_date between r.date_since and r.date_until
 group by r.id_range