我有一个运行缓慢的查询,我想出了一个更快的选择,但我希望获得一些帮助,以了解为什么原始查询这么慢。
我的问题的简化版使用两个表。第一个表的简化版本称为配置文件,
`profiles` (
`id` int(11),
`title` char(255),
`body` text,
`pin` int(11),
PRIMARY KEY (`id`),
UNIQUE KEY `pin` (`pin`)
)
我的第二张桌子的简化版电话是
`calls` (
`id` int(11),
`pin` int(11),
`duration` int(11),
PRIMARY KEY (`id`),
KEY `ivr_id` (`pin`)
)
我的查询应该获得完整的配置文件,并加上配置文件收到的呼叫数量。我正在使用的查询是
SELECT profiles.*, COUNT(*) AS num_calls
FROM profiles
LEFT JOIN calls
ON profiles.pin = calls.pin
GROUP BY profiles.pin
使用大约100个配置文件和大约250,000个呼叫,此查询大约需要10秒钟,这很慢。
如果我修改查询以仅从配置文件而不是所有列中选择标题,则查询会更快。如果我修改查询以删除分组依据,其速度也快得多。如果我只是从个人资料表中选择所有内容,那么它也是一个快速查询。
我的实际配置文件表还有更多的文本和字符字段。选择的文本字段越多,查询速度越差。当文本字段不包含在JOIN或GROUP中时,为什么这些文本字段会导致查询如此缓慢?
我想出了一个稍有不同的查询,该查询要快得多,不到半秒钟。该查询是:
SELECT profiles.*, temp.readings
FROM profiles
LEFT JOIN (
SELECT pin ,COUNT(*) AS readings
FROM calls
GROUP BY pin
) AS temp
ON temp.pin=profiles.pin
虽然我认为我已经解决了速度问题,但是我想了解在第一次查询中是什么导致了问题。
=========更新=======
我刚刚配置了两个查询,并且整个速度差异都在“发送数据”部分中。慢查询大约10秒,快查询大约0.1秒
=========更新2 ========
与@scaisEdge讨论之后,我想我可以改写我的问题。考虑一个表T1,它具有〜40列,其中8个是TEXT类型,并且具有〜100行,而表T2具有5列的INT和VARCHAR类型,具有〜250,000行。为什么会这样:
SELECT T1.* FROM T1 is fast
SELECT T1.* FROM T1 JOIN T2 GROUP BY T1.joinfield is slow
如果selectfield是INT或VARCHAR,则 SELECT T1.selectfield FROM T1 JOIN T2 GROUP BY T1.joinfield
很快
答案 0 :(得分:0)
这应该是因为
第一个查询将100个配置文件与250,000个调用连接起来,然后按result减少返回的行分组。而选择配置文件。*表示对每个匹配行都具有对配置文件表数据的完全访问权限
然后第二个查询将100个配置文件与TEMP的子查询返回的行数(可能少于250,000)相结合,从而减少了对表配置文件数据的访问次数
而不是个人资料。*尝试仅访问引脚列
SELECT profiles.pin, COUNT(*) AS num_calls
FROM profiles
LEFT JOIN calls ON profiles.pin = calls.pin
GROUP BY profiles.pin
作为建议,您应该注意,仅在5.7版之前的MySQL版本才允许对第一个查询使用group by,因为在select子句中使用不带column列的group by列,并且不受聚合函数的影响并且在DEFALT中不允许在GROUP BY中提及并产生错误..