如何优化此查询?

时间:2011-08-08 12:18:57

标签: sql performance oracle

我有桌子: A(ID_A,VALID_FROM,DATA ......) B(ID_B,ID,T1,T2,T3,DATE)

表A可以包含历史数据(例如,在给定时期内有效的数据) 我需要从表B中选择与表A中的appropritate记录连接的记录(从表A我需要行,其中b.id = a.id_a,记录在b.date有效)

select * 
from B, (select * from (select * from A where a.id_a = b.id and a.valid_from <= b.date order by valid_from desc) where rownum = 1)
where b.id = a.id_a

3 个答案:

答案 0 :(得分:2)

答案 1 :(得分:1)

这不是更优化,但可能更具可读性:

select *  
from A a, B b
Where 
a.id_a = b.id 
and a.valid_from = (select max(valid_from) 
                    from A 
                    where id_a = b.id 
                    and valid_from <= b.date)
order by valid_from desc

我以前见过这个问题,我知道优化它的最好方法是将一个valid_to列放到表A上。

对于最新记录,这应包含Oracle可以处理的最大日期 每当你创建一个较新版本的记录时,用创建新记录的时间更新它(减去毫秒以避免重叠),所以你有这样的东西:

ID Valid_from                Valid_to
1  01/01/2011 12.34.56.0000  02/01/2011 12.34.56.0000
1  02/01/2011 12.34.56.0001  03/01/2011 12.34.56.0000
1  03/01/2011 12.34.56.0001  31/12/9999 23.59.59.9999

然后你可以像这样查询:

select *  
from A a, B b
Where 
a.id_a = b.id 
and b.date between a.valid_from and a.valid_to
order by valid_from desc

使用日期列上的索引,性能应该没问题。

答案 2 :(得分:0)

我已经接受了StevieG的回答并对其进行了扩展。如果没有valid_to列,则需要编写棘手的子查询。我建议使用LEAD分析函数来查找当前有效期的结束并使用它。这是子查询和valid_to列的替代方法。

LEAD分析函数查看当前数据集中的行,并查找下一个valid_from日期,并将其用作当前期间的结尾。

我的查询如下所示。它将您提供的样本数据合并到with子句中。

with table_a as (
  select 1 as id, 'XXX1' as data, date '2009-01-01' as valid_from from dual union all
  select 1 as id, 'XXX2' as data, date '2009-05-30' as valid_from from dual union all
  select 1 as id, 'XXX3' as data, date '2010-01-11' as valid_from from dual union all
  select 2 as id, 'YYY' as data, date '1999-01-01' as valid_from from dual
),
table_b as (
  select 1 as id, 1 as id_a, date '2009-02-01' as date_col from dual union all
  select 2 as id, 2 as id_a, date '2009-09-12' as date_col from dual union all
  select 3 as id, 1 as id_a, date '2009-06-30' as date_col from dual
)
select *
from table_b b
  join (
    select 
      id, 
      valid_from, 
      lead(valid_from, 1, date '9999-12-31') over (partition by a.id order by a.valid_from) as valid_to
    from table_a a
) a on (a.id = b.id_a)
where 
  a.valid_from <= b.date_col and 
  b.date_col < a.valid_to