这是我的网络应用程序中迄今为止最慢的查询。
SELECT prof.user_id AS userId,
prof.first_name AS first,
prof.last_name AS last,
prof.birthdate,
prof.class_string AS classes,
prof.city,
prof.country,
prof.state,
prof.images,
prof.videos,
u.username,
u.avatar,
(SELECT Count(*)
FROM company_member_sponsorship
WHERE member_id = prof.user_id
AND status = 'sponsored') AS sponsor_count,
(SELECT Count(*)
FROM member_schedules
WHERE user_id = prof.user_id) AS sched_count
FROM member_profiles prof
LEFT JOIN users u
ON u.id = prof.user_id
ORDER BY ( prof.images + prof.videos * 5 + (
CASE
WHEN prof.expire_date > :time THEN 50
ELSE 0
end ) + sponsor_count * 20 + sched_count * 4
) DESC,
prof.last_name ASC
LIMIT :start, :records
即使在所有级别上发生大量查询,网站上的其他所有内容也只需不到一秒钟即可加载。这个大概需要3-4秒。
显然,表扫描会导致速度减慢。我明白为什么;第一个表有50,000多行,第二个表有160,000多行。
有什么方法可以优化此查询以使其更快?
如果情况变得更糟,我可以随时查看我的代码,并为配置文件表中的赞助和事件保持一个统计数据,就像我对图像和视频一样,但我想避免它。
编辑:我在查询中添加了EXPLAIN的结果。
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY prof ALL NULL NULL NULL NULL 44377 Using temporary; Using filesort
1 PRIMARY u eq_ref PRIMARY PRIMARY 3 mxsponsor.prof.user_id 1
3 DEPENDENT SUBQUERY member_schedules ref user_id user_id 3 mxsponsor.prof.user_id 6 Using index
2 DEPENDENT SUBQUERY company_member_sponsorship ref member_id member_id 3 mxsponsor.prof.user_id 2 Using where; Using index
EDIT2:
我最后通过维护会员资料中的计数来解决问题。无论在何处添加/删除赞助/事件,我都会调用一个扫描赞助/事件表的函数,并更新该成员的计数。可能仍有一种方法可以优化这样的查询,但是我们很快就会发布这个网站,所以我现在要使用快速而肮脏的解决方案。
答案 0 :(得分:2)
无法保证可行,但请尝试使用join
和group by
而不是内部选择:
SELECT prof.user_id AS userId,
prof.first_name AS first,
prof.last_name AS last,
prof.birthdate,
prof.class_string AS classes,
prof.city,
prof.country,
prof.state,
prof.images,
prof.videos,
u.username,
u.avatar,
Count(cms.id) AS sponsor_count,
Count(ms.id) AS sched_count
FROM member_profiles prof
LEFT JOIN users u
ON u.id = prof.user_id
LEFT JOIN company_member_sponsorship cms
ON cms.member_id = prof.user_id
AND cms.status = 'sponsored'
LEFT JOIN member_schedules ms
ON ms.user_id = prof.user_id
GROUP BY u.id
ORDER BY ( prof.images + prof.videos * 5 + (
CASE
WHEN prof.expire_date > :time THEN 50
ELSE 0
end ) + sponsor_count * 20 + sched_count * 4
) DESC,
prof.last_name ASC
LIMIT :start, :records
如果没有那么好,那么explain
该查询会有所帮助。