Slow IN()MySQL查询优化

Slow IN()MySQL查询优化,mysql,sql,database,Mysql,Sql,Database,我有下面的SQL查询,它工作得很好,但处理速度非常慢,需要3到5秒。我已经在slug和checksum列上创建了索引,但是由于IN子句在5000到10000行之间运行,这还不够快。 我读到有一种方法可以通过使用临时表和/或联接来改进它,但我找不到一种方法可以让它工作 数据库引擎是MySQL上的InnoDB。 任何帮助都将不胜感激 SELECT name AS personName, slug AS personSlug, COUNT(slug) AS person

我有下面的SQL查询,它工作得很好,但处理速度非常慢,需要3到5秒。我已经在slug和checksum列上创建了索引,但是由于IN子句在5000到10000行之间运行,这还不够快。 我读到有一种方法可以通过使用临时表和/或联接来改进它,但我找不到一种方法可以让它工作

数据库引擎是MySQL上的InnoDB。 任何帮助都将不胜感激

SELECT name AS personName, 
       slug AS personSlug, 
       COUNT(slug) AS personCount 
  FROM person
 WHERE checksum IN
         ( SELECT checksum 
             FROM person 
            WHERE slug = 'john-doe' )  
   AND NOT (slug = 'john-doe')
 GROUP BY personName 
 ORDER BY personCount DESC
经常将其更改为“不存在”有助于提高性能:

SELECT name AS personName, slug AS personSlug, COUNT(slug) AS personCount
FROM person p
WHERE EXISTS (SELECT 1
              from person p2
              WHERE p2.slug = 'john-doe' and p2.checksum = p.checksum
             ) AND
     NOT (slug = 'john-doe')
GROUP BY personName
ORDER BY personCount DESC;

为了提高性能,您需要personchecksum、slug上的索引。

如果没有看到一些示例数据,我无法完全理解您查询的目的。但看起来您正在尝试查找与“john doe”关联的校验和匹配的所有校验和,但没有slug=“john doe”-因此搜索某种类型的重复项

下面的自联接应该可以为您做到这一点

SELECT
    p.name AS personName,
    p.slug AS personSlug,
    COUNT(p.slug) AS personCount
FROM
    person AS p
INNER JOIN
    person AS p2
ON
    p.checksum = p2.checksum
WHERE
    p2.slug = 'john-doe'
    AND p.slug <> 'john-doe'
GROUP BY personName
ORDER BY personCount DESC

根据我的经验,左连接比IN子句和任何类型的子查询都要快

SELECT p1.name AS personName, p1.slug AS personSlug, COUNT(p1.slug) AS personCount 
FROM person p1
LEFT JOIN person p2 on p1.checksum=p2.checksum and p2.slug = 'john-doe'
WHERE p1.slug != 'john-doe'
AND p2.slug is NOT NULL
GROUP BY personName 
ORDER BY personCount DESC
这大致意味着:我想得到的名字和鼻涕虫的鼻涕虫不是“john doe”,其中至少有一行与鼻涕虫“john doe”具有相同的校验和

如果要查找没有匹配“john doe”记录的记录,则只需更改一个子句:

SELECT p1.name AS personName, p1.slug AS personSlug, COUNT(p1.slug) AS personCount 
FROM person p1
LEFT JOIN person p2 on p1.checksum=p2.checksum and p2.slug = 'john-doe'
WHERE p1.slug != 'john-doe'
AND p2.slug iS NULL
GROUP BY personName 
ORDER BY personCount DESC

顺便说一句,不相等运算符xy在这里比不等于x=yAs更为常规,因为我可以看到您改变了查询的含义?你的意思是在哪里存在?从slug='john doe'和checksum=p的人中选择1。checksum和slug'john doe'?@plaix。是的。你是对的,应该存在而不是不存在。谢谢你的回答戈登。不幸的是,这并没有帮助提高性能,或者说是令人惊讶的最差性能。你们有校验和的索引吗,slug?我有校验和的索引,slug。我已经三次检查了您的解决方案,但运行时间仍然与我最初的请求相同或更长。非常感谢。它将执行时间从3秒减少到5秒,达到300毫秒@Anthony你试过Gordon Linoff的答案吗?通常EXISTS更快,因为它短路。@plax我尝试了Gordon的答案,但没有提高性能。@MikeBrant。我猜slug上有一个索引,过滤功能非常强。这可能会使这个版本更有效。我的版本无法利用它,因为=筛选在子查询上,而不是外部查询上。非常感谢您的回答。它工作得很好。看,迈克的回答也很有效,从我测试的结果来看,他们的表现也很相似。但也许左连接更好?我使用左连接是因为我不知道需要检索什么。如果您想查找不匹配的校验和,那么LEFT JOIN允许这样做,因此我进行了第二次查询。对于小表和一致索引,内部联接和左联接之间的性能差异往往可以忽略不计。如果您操作超过100000条记录,您可能希望开始对这两条记录进行基准测试。