我在朋友提要查询方面遇到了奇怪的麻烦 - 这是背景:
我有 3 张桌子
checkin - around 13m records
users - around 250k records
friends - around 1.5m records
在签入表中 - 它列出了用户执行的活动。(这里有很多索引,但是user_id,created_at和(user_id,created_at)上有一个索引。users表只是基本用户信息user_id上有一个索引。friends表有user_id,target_id和is_approved。 (user_id, is_approved) 字段上有一个索引。
在我的查询中,我试图只删除任何用户的基本朋友提要 - 所以我一直在这样做:
SELECT checkin_id, created_at
FROM checkin
WHERE (user_id IN (SELECT friend_id from friends where user_id = 1 and is_approved = 1) OR user_id = 1)
ORDER by created_at DESC
LIMIT 0, 15
查询的目标只是为所有用户的朋友以及他们的活动提取 checkin_id 和 created_at。这是一个非常简单的查询,但是当用户的朋友最近有大量活动时,这个查询非常快,下面是解释:
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY checkin index user_id,user_id_2 created_at 8 NULL 15 Using where
2 DEPENDENT SUBQUERY friends eq_ref user_id,friend_id,is_approved,friend_looku... PRIMARY 8 const,func 1 Using where
作为解释,user_id 是 user_id 的简单索引 - 而 user_id_2 是 user_id 和 created_at 的索引。在friends表上,friends_lookup是user_id和is_approved的索引。
这是一个非常简单的查询并在以下位置完成:显示第 0 - 14 行(总共 15 行,查询耗时 0.0073 秒)。
但是,当用户的好友活动不是最近的并且没有很多数据时,相同的查询大约需要 5-7 秒,并且它具有与前一个查询相同的 EXPLAIN - 但需要更长的时间。
它似乎对更多的朋友没有影响,它似乎随着最近的活动而加速。
是否有任何提示可以让任何人优化这些查询,以确保无论活动如何,它们都以相同的速度运行?
服务器设置
这是一个运行 16GB RAM 的专用 MySQL 服务器。它运行的是 Ubuntu 10.10,MySQL 的版本是 5.1.49
更新
所以大多数人建议删除 IN 块并将它们移动到 INNER JOIN 中:
SELECT c.checkin_id, c.created_at
FROM checkin c
INNER JOIN friends f ON c.user_id = f.friend_id
WHERE f.user_id =1
AND f.is_approved =1
ORDER BY c.created_at DESC
LIMIT 0 , 15
这个查询差了 10 倍——正如 EXPLAIN 中所报告的:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE f ref PRIMARY,user_id,friend_id,is_approved,friend_looku... friend_lookup 5 const,const 938 Using temporary; Using filesort
1 SIMPLE c ref user_id,user_id_2 user_id 4 untappd_prod.f.friend_id 71 Using where
此查询的目标是在同一个查询中获取所有朋友活动以及您的活动(而不必创建两个查询并将结果合并在一起并按 created_at 排序)。我也无法删除 user_id 上的索引,因为它是另一个查询的重要部分。
有趣的部分是当我在一个没有很多活动的用户帐户上运行这个查询时,我得到了这个解释:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE f index_merge PRIMARY,user_id,friend_id,is_approved,friend_looku... user_id,friend_lookup 4,5 NULL 11 Using intersect(user_id,friend_lookup); Using wher...
1 SIMPLE c ref user_id,user_id_2 user_id 4 untappd_prod.f.friend_id 71 Using where
有什么建议吗?