【问题标题】:How to write this query [closed]如何编写此查询 [关闭]
【发布时间】:2012-01-19 16:22:37
【问题描述】:

我被困在一个查询中,需要您的帮助和建议。情况是:

我有一个结构为

的表

JOB_ID、ITEM_ID、NEW_ITEM_ID、状态

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

现在我想编写一个查询,它只从表中选择那些状态为 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。

【问题讨论】:

  • 您忘记在标签中指定firebirddb2
  • 嘿。 @Algorithmist:您实际使用的是哪个 DBMS?
  • @Algorithmist:那么,请告诉我,为什么要使用 MySQL 和 PostgreSQL 标签?
  • @Tomalak 我只想要逻辑。这就是为什么。你有什么建议吗。
  • 我建议以过于本地化来结束这个问题。

标签: sql performance oracle oracle11g query-optimization


【解决方案1】:

最简单的方法是查询所有 ITEM_ID 和 NEW_ITEM_ID,状态为 SB,然后再进行如下查询:

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).

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

【讨论】:

  • 我也这样做了,但也花费了太多时间。
【解决方案2】:

试试这个:

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

【讨论】:

  • 你应该开始在你的答案中写words;代码示例补充说明!
【解决方案3】:

听起来您正在寻找 (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 )

【讨论】:

    【解决方案4】:

    “这个表将包含数百万条记录,大约 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 的服务器,则此选项对您开放(如果您要运行具有数百万行表的应用程序数据库,这两个条件都应该为真_。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-23
      • 2011-02-20
      • 2015-08-14
      • 1970-01-01
      • 2021-01-15
      相关资源
      最近更新 更多