Sql 如何编写此查询
我陷入了一个疑问,需要你的帮助和建议。情况是: 我有一张桌子,结构如下 作业ID、项目ID、新项目ID、状态 其中job_id是主键,状态可以是AC、SB 现在我想写一个查询,只从表中选择状态为AC的行,并且状态为SB的行中没有ITEM_ID或NEW_ITEM_ID。我已经写了一个查询,但它需要很多时间,所以请帮助我编写优化的查询。这就是我写的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
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我只需要逻辑。这就是为什么。您有什么建议吗?我建议结束这个问题,因为它太本地化了。我也这么做了,但它也是花费太多时间。你应该开始在你的答案中写单词;代码示例补充解释!