改进查询

时间:2013-05-09 19:56:38

标签: mysql sql

我正在尝试做一个简单的SQL查询:

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

运行需要很长时间,我认为它与where语句中的select(有大量id)有关,但我无法想出一种方法来改进它。

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

编辑:

数据库系统:MySql

Id已编入索引,但不是此表中的主键;这是一把外键。

4 个答案:

答案 0 :(得分: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

这将获得营销中属于“电子邮件”类型的所有行,并且不存在类型为“字母”的ID以匹配。如果您想要另一组,请使用IS NOT NULL。 id列上的正确索引是最大执行速度所需要的,类型为覆盖列。

答案 1 :(得分: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

答案 2 :(得分: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;

编写此类查询的三种主要方式是NOT IN,NOT EXISTS(相关)或LEFT JOIN / IS NULL。 Quassnoi将它们与MySQL(上面的链接),SQL ServerOraclePostgreSQL进行比较。

答案 3 :(得分: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执行排序。