从MySQL 5.6中获取一些奇怪的行为。以下查询应该从连接中选择一些简单数据。哪个工作正常。
SELECT
f.followID,
l.object_id,
l.created_at,
ROUND(UNIX_TIMESTAMP(l.created_at)/(3600)) window
FROM fb_follow f LEFT JOIN fb_likes l ON f.followID = l.user_id
WHERE f.profileID = 1
AND l.created_at > '20171119' LIMIT 1000;
当我错误地包含l.created_at
行的副本时,会发生奇怪的事情。
SELECT
f.followID,
l.object_id,
l.created_at,
l.created_at,
ROUND(UNIX_TIMESTAMP(l.created_at)/(3600)) window
FROM fb_follow f LEFT JOIN fb_likes l ON f.followID = l.user_id
WHERE f.profileID = 1
AND l.created_at > '20171119' LIMIT 1000;
查询执行时间从~600ms到~350ms(对于f.profileID
的不同值重复。查询时间较短的原因是什么?我的期望是,由于数据量较少,它至少会花费更少的时间回来?
答案 0 :(得分:1)
两个缓存
将SELECT
更改为SELECT SQL_NO_CACHE
,无法使用"查询缓存"。
通常在使用查询缓存时,查询时间为1毫秒或更短。 350ms表示它不是QC。
另一个主要缓存是InnoDB的buffer_pool。 (你 使用InnoDB,对吗?)当你第一次运行查询时,可能需要点击磁盘来获取索引和/或数据块。第二次,那些块可能仍然缓存在buffer_pool(在RAM中),因此查询会更快。
差异通常是10倍。但是有很多例外。 600 vs 350不适合这种模式,但这是不确定的。
所以,当时间做两件事时:
<强> EXPLAIN 强>
请为每个变体运行EXPLAIN SELECT ...
。如果存在任何差异(我怀疑),这可能会给出新的洞察力,为什么&#34;重复一行改变了时间&#34;。
<强> JOIN 强>
当您不需要时,请不要使用LEFT
。它让读者感到困惑。由于您明确过滤了f.profileID = 1
,因此会忽略LEFT
(并且可以将其删除)。
ORDER BY
LIMIT
没有ORDER BY
通常是愚蠢的。你想要哪1000行?添加ORDER BY
会使决策明确。是的,它可能会减慢查询速度。
有用的索引
为了获得更好的表现:
`f` needs INDEX(followID, profileID) -- in this order
`u` needs INDEX(created_at)