如何编写此查询

时间:2011-12-13 19:49:24

标签: sql performance oracle oracle11g query-optimization

我遇到了疑问,需要你的帮助和建议。情况是:

我有一个结构为

的表

JOB_ID,ITEM_ID,NEW_ITEM_ID,STATUS

其中job_id是主键,状态可以是AC,SB。

现在我想编写一个查询,只选择那些具有STATUS作为AC的表中的行,并且ITEM_ID或NEW_ITEM_ID都不在状态为SB的行中。我已经编写了一个查询但它需要一个很多时候请帮我写出优化的查询。这就是我写的

SELECT * FROM (
      SELECT JOB_ID,NEW_ITEM_ID,ITEM_ID,STATUS 
      FROM X1 
      WHERE  STATUS='AC' 
      AND NEW_ITEM_ID IS NOT NULL
      MINUS
      ( SELECT T1.JOB_ID,T1.NEW_ITEM_ID ,T1.ITEM_ID ,T1.STATUS 
        FROM ( SELECT * 
               FROM X1
               WHERE STATUS IN 'AC' 
               AND NEW_ITEM_ID IS NOT NULL  ) T1 
      , ( SELECT * 
          FROM X1 
          WHERE STATUS IN ('PR','SB') 
          AND NEW_ITEM_ID IS NOT NULL  ) T2
    WHERE ( T2.ITEM_ID IN (T1.ITEM_ID,T1.NEW_ITEM_ID) 
                  OR T2.NEW_ITEM_ID IN  (T1.ITEM_ID,T1.NEW_ITEM_ID) 
       )
    AND T1.STATUS!=T2.STATUS 
   )
 ) T

编辑

此表格将包含数百万条记录,大约30M左右。

4 个答案:

答案 0 :(得分:1)

最简单的方法是让查询选择状态为SB的所有ITEM_ID和NEW_ITEM_ID,然后再进行另一个查询:

SELECT * FROM table WHERE STATUS = 'AC' AND WHERE ITEM_ID NOT IN (the results of the previous query) AND WHERE NEW_ITEM_ID NOT IN (the results of the query for NEW_ITEM_IDs mentioned above)

虽然只是一个想法,但我认为应该有正确的语法。

答案 1 :(得分:0)

试试这个:

 select * from status where STATUS ='AC' or (STATUS ='SB' and ITEM_ID  is null) or  or (STATUS ='SB' and NEW_ITEM_ID is null)

答案 2 :(得分:0)

听起来你正在寻找(1)状态为AC的行和(2)没有其他行,其中item_id或new_item_id匹配且状态为SB?

怎么样:

SELECT job_id, item_id, new_item_id, status
  FROM x1 a
 WHERE a.status = 'AC'
   AND NOT EXISTS (SELECT 1 FROM x1 b
                    WHERE b.status = 'SB'
                      AND ( b.new_item_id = a.item_id
                            OR b.item_id = a.new_item_id )

答案 3 :(得分:0)

  

“此表将包含数百万条记录,大约30M”

这是一个至关重要的信息,但缺少其他一些关键统计数据。有多少行符合“PR”,“SB”和“AC”的状态?有多少行填充new_item_id?这些列是否已编入索引?

您在子查询中选择*来自x1'。 SELECT *是不好的做法,等待发生的错误。但是这里是灾难性的,因为你不使用任何列,但是你强迫数据库读取结果集中每个条目的整行。行越长越昂贵。在子查询中,如果可能的话,你真的应该只关注索引。

理想情况下,您将拥有X1上的索引(STATUS,NEW_ITEM_ID,ITEM_ID,JOB_ID)。然后你根本不会碰到桌子。但至少你需要一个索引(STATUS,NEW_ITEM_ID)。只有STATUS上的索引对你没有任何好处,除非STATUS具有高选择性 - 数百个不同的值,均匀分布。 (这似乎不太可能:根据我的经验,大多数状态列都有一些不同的状态_。

您发布的查询会在表格X1中点击三次;这需要很长时间。所以主要是减少你击中桌子的次数。这是子查询因子可以帮助的地方:

with data as (  select job_id, new_item_id, item_id, status 
                from x1 
                where  status in ('PR','SB', 'AC' ) 
                and new_item_id is not null )
select t1.* 
from data t1
     , data t2
where t1.status = 'AC'
and t2.status in ( 'PR','SB' )
abd (t2.new_item_id in ( t1.new_item_id, t1.item_id )
     or t2.item_id in ( t1.new_item_id, t1.item_id ) )
/

因此,这个查询只会在表中点击一次,并且有利的索引甚至不会一次。

如果查询仍然花费太多时间 - 或者你不能纠结一个有用的索引 - 另一个改进大规模表执行时间的选项是并行查询。如果您拥有Enterprise Edition许可证和具有足够CPU的服务器,则此选项对您是开放的(如果您要运行具有数百万行表的应用程序数据库,则这两个条件都应为true。

with data as (  select /*+ parallel (x1, 4) */
                        job_id, new_item_id, item_id, status 
                 from x1 
                 ...