Slow IN()MySQL查询优化
我有下面的SQL查询,它工作得很好,但处理速度非常慢,需要3到5秒。我已经在slug和checksum列上创建了索引,但是由于IN子句在5000到10000行之间运行,这还不够快。 我读到有一种方法可以通过使用临时表和/或联接来改进它,但我找不到一种方法可以让它工作 数据库引擎是MySQL上的InnoDB。 任何帮助都将不胜感激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
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条记录,您可能希望开始对这两条记录进行基准测试。