删除子选择以优化此查询

时间:2012-12-09 20:35:55

标签: oracle query-optimization

我有这个查询需要大约5分钟来返回结果集,我无法找到更好的方法来做到这一点。有问题的表在任何时候都有大约15或2千万行,其模式可以概括为

create table conversation(
  id raw, -- GUID
  vendor varchar,
  snumber number
  rcvdate date
)

我们存储从供应商发送或向供应商发送的消息,每条消息都有一个由所有会话(相关消息集)共享的序列号。问题出现是因为供应商可以拥有父代,并且消息可以包含父代码(我们可以假设我们在查询时知道供应商的代码及其父代码)。假设A和B是2个具有共同父P的供应商,该表可能看起来像

Vendor  snumber    date
------------------------------
A       1          01-JAN-2012
P       1          02-JAN-2012
A       1          02-JAN-2012
A       2          03-JAN-2012
P       2          03-JAN-2012
B       3          03-JAN-2012
P       3          04-JAN-2012
A       2          04-JAN-2012

我们需要查询来自/到A的最后N条消息,并使用vendor = A OR(供应商= P和另一条供应商= A和相同的狙击手的记录)获取消息,即:

Vendor  snumber    date
------------------------------
A       1          01-JAN-2012
P       1          02-JAN-2012
A       1          02-JAN-2012
A       2          03-JAN-2012
P       2          03-JAN-2012
A       2          04-JAN-2012

我所做的是将对话存储在临时表T(id,snumber)中,然后返回

    select * from ( 
       select * from conversations c 
       where 
       exists (select id from T where T.id  = C.id) or 
       ( c.vendor=l_parent and exists (select snumber from T where T.snumber=c.snumber )
   ) where rownum <= l_N

这两个子查询正在扼杀性能。对话表在此示例中包含的所有列中都有索引。 我认为必须是一个聪明的方法来分组这些信息,而不必使用临时表或子查询,但我想不出一个。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:0)

听起来你想要这样的东西:

SQL> select vendor, snumber, rcvdate
  2    from (select vendor, snumber, rcvdate,
  3                 max(case when vendor = 'A' then 'Y' end) over (partition by snumber) has_vendor
  4            from conversation
  5           where vendor in ( 'A', 'P' )
  6           order by rcvdate desc)
  7   where has_vendor = 'Y'
  8     and rownum <= 100
  9   order by rcvdate;

V    SNUMBER RCVDATE
- ---------- --------------------
A          1 01-jan-2012 00:00:00
P          1 02-jan-2012 00:00:00
A          1 02-jan-2012 00:00:00
P          2 03-jan-2012 00:00:00
A          2 03-jan-2012 00:00:00
A          2 04-jan-2012 00:00:00

即。

max(case when vendor = 'A' then 'Y' end) over (partition by snumber) has_vendor

如果该狙击手中有'A'供应商,那么你想要为“P”不是供应商返回,否则不会。