2013-05-09 79 views
3

我试图做一个简单的SQL查询:提高查询

SELECT DISTINCT id 
FROM marketing 
WHERE type = 'email' 
    AND id NOT IN (
       SELECT id 
       FROM marketing 
       WHERE type = 'letter' 
       ) 
ORDER BY id; 

这需要很长的时间来运行,我认为它与在WHERE语句选择做(有大量的ID),但我不能想出一个方法来改善它。

首先,这可能是查询速度如此之慢的原因,其次是如何改进它的建议?

编辑:

数据库系统:MySQL的

标识被索引,但是却并不在此表的主键;它是一个外键。

+1

你的表有多大,'type'有索引? – nacholibre 2013-05-09 19:59:03

+1

'WHERE type ='email''和'WHERE type ='letter''似乎是多余的。你基本上说类型必须是“电子邮件”,但是再次检查它不是“字母”。你不能只拿出嵌套的SELECT? – 2013-05-09 19:59:36

+4

整个'不在'位似乎是多余的。如果你用'type ='email''找到了一条记录,那么它怎么可能在'type ='letter''的记录列表中呢? – 2013-05-09 20:00:17

回答

1

这是您的查询的替代方法,但根据Quassnoi here (MySQL)它应该具有相似的性能。

select email.id 
    from marketing email 
left join marketing letter on letter.type='letter' and letter.id=email.id 
    where email.type='email' and letter.id is null 
group by email.id 
order by email.id; 

编写这种类型的查询的三种主要方式是不是,不存在(相关)或左连接/空。 Quassnoi将它们比作MySQL(上面的链接),SQL ServerOraclePostgreSQL

2

这种类型的查询有一个已知模式:获取所有不匹配另一个集合的行。

select id from marketing m1 
left outer join marketing m2 on m1.id = m2.id and m2.type = 'letter' 
where m1.type = 'email' and m2.id IS NULL 

这将获得市场营销中'email'类型的所有行,并且不存在与类型'letter'匹配的id。如果你想要另一个集合,使用IS NOT NULL。在id列上的正确索引是您最大执行速度所需的全部内容,其中type为覆盖列。

2
select distinct id 
from marketing a 
where type = 'email' 
and not exists (
      select 'X' 
      from marketing b 
      where a.id = b.id 
      and type = 'letter') 
order by id 
1

您还可以将此查询短语作为聚合查询。你正在寻找的条件是,一个id至少有一个排,其中type = 'email',且行其中type = 'letter'

select id 
from marketing m 
group by id 
having SUM(case when type = 'letter' then 1 else 0 end) = 0 and 
     SUM(case when type = 'email' then 1 else 0 end) > 0 

这是可能的,这条查询与marketing(id, type)指数运行得更快。 order by id在MySQL中是多余的,因为group by执行排序。