Sql 如何编写此查询

Sql 如何编写此查询,sql,performance,oracle,oracle11g,query-optimization,Sql,Performance,Oracle,Oracle11g,Query Optimization,我陷入了一个疑问,需要你的帮助和建议。情况是: 我有一张桌子,结构如下 作业ID、项目ID、新项目ID、状态 其中job_id是主键,状态可以是AC、SB 现在我想写一个查询,只从表中选择状态为AC的行,并且状态为SB的行中没有ITEM_ID或NEW_ITEM_ID。我已经写了一个查询,但它需要很多时间,所以请帮助我编写优化的查询。这就是我写的 SELECT * FROM ( SELECT JOB_ID,NEW_ITEM_ID,ITEM_ID,STATUS FROM X

我陷入了一个疑问,需要你的帮助和建议。情况是:

我有一张桌子,结构如下

作业ID、项目ID、新项目ID、状态

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

现在我想写一个查询,只从表中选择状态为AC的行,并且状态为SB的行中没有ITEM_ID或NEW_ITEM_ID。我已经写了一个查询,但它需要很多时间,所以请帮助我编写优化的查询。这就是我写的

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。

最简单的方法是使用一个查询选择所有项目ID和状态为SB的新项目ID,然后使用另一个类似以下的查询:

从表中选择*,其中STATUS='AC'和WHERE ITEM_ID NOT IN(上一次查询的结果)以及WHERE NEW_ITEM_ID NOT IN(上述新_ITEM_ID的查询结果)

这只是一个想法,但如果语法正确,我认为应该可以做到。

试试这个:

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

听起来您正在查找(1)状态为AC的行,以及(2)没有其他行的项目id或新项目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 )
“这个表将包含数百万条记录,比如说3000万条左右”

这是一条重要的信息,但缺少其他几个关键数据。有多少行与“PR”、“SB”和“AC”的状态匹配?有多少行填充了
新项目\u id
?这些列有索引吗

您可以在子查询中“从x1中选择*”。SELECT*是一个坏习惯,一个等待发生的错误。然而,这是灾难性的,因为您不使用任何列,但是您强制数据库读取结果集中每个条目的整行。行越长,成本越高。在子查询中,如果可能的话,实际上应该只删除索引

理想情况下,您应该在X1上有一个索引(状态、新项目ID、项目ID、作业ID)。那你就不会撞到桌子了。但至少你需要一个索引(状态、新项目ID)。一个仅仅基于状态的索引不会对你有任何好处,除非状态是高度选择性的——几百个不同的值,均匀分布。(这似乎不太可能:根据我的经验,大多数状态栏都有几个不同的状态。)

您发布的查询命中表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的服务器,则此选项对您开放(如果要运行具有数百万行表的应用程序数据库,则这两个条件都应为真。)

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

您忘了在tagsHeh中指定
firebird
db2
。@算法学家:您实际使用的是哪种DBMS?@Algorithmist:那么,请告诉我,为什么使用MySQL和PostgreSQL标记?@Tomalak我只需要逻辑。这就是为什么。您有什么建议吗?我建议结束这个问题,因为它太本地化了。我也这么做了,但它也是花费太多时间。你应该开始在你的答案中写单词;代码示例补充解释!