我有以下SELECT:
SELECT a.userid,
(SELECT name FROM photos WHERE userid=a.userid AND type='profile' LIMIT 1) AS photo,
(SELECT attractive FROM photos WHERE userid=a.userid AND type='profile' LIMIT 1) AS attractive,
IF(a.domain="domanin.com",1,2) AS preferredDomain,
IF(a.domain LIKE "%domain.com",1,2) AS preferredSubDomain
FROM users AS a
WHERE a.gender = 1
AND a.visible = 1
AND a.active = 1
AND a.completed = 1
AND a.approved = 1
HAVING photo IS NOT NULL
ORDER BY preferredDomain ASC,
attractive DESC,
a.lastlogin DESC,
preferredSubDomain ASC
LIMIT 100;
这需要5-6秒才能运行。
如果我删除Order By
,则需要0.23秒才能运行。
我假设这是因为SELECT
必须先生成内部SELECTS才能进行排序?这是正确的吗? users表有60,000个条目。
有人可以就如何更好地构建此查询提供一些建议吗?
答案 0 :(得分:1)
尝试使用连接而不是嵌套查询,例如:
SELECT
a.userid,
p.name,
p.attractive,
IF(a.domain="domain.com",1,2) AS preferredDomain,
IF(a.domain LIKE "%domain.com",1,2) AS preferredSubDomain
FROM users AS a
JOIN photos AS p ON (p.userid = a.userid AND p.type = 'profile')
WHERE
a.gender = 1
AND a.visible = 1
AND a.active = 1
AND a.completed = 1
AND a.approved = 1
HAVING photo IS NOT NULL
ORDER BY preferredDomain ASC, attractive DESC, a.lastlogin DESC, preferredSubDomain ASC
LIMIT 100;
可以在此处找到有关连接语法的文档: http://dev.mysql.com/doc/refman/5.7/en/join.html
答案 1 :(得分:0)
子查询不是恶棍。使用ORDER BY
必须在排序之前评估所有60K行。如果没有ORDER BY
,可能需要查看更少的行。
@ StephanGarle建议使用JOIN
可以加快查询速度,尤其是因为两个子查询都被JOIN
替换。
photos
需要INDEX(type, userid)
(按任意顺序)。但更好的是拥有一个“覆盖”索引:(type, userid, name, attractive)
,其中前两个是任意顺序,后两个是任意顺序。
photo
有两种方式NULL
-
name
可以是NULL
或photos
中没有该用户标识符的行并输入“个人资料”。)这是哪一个?要涵盖这两种情况,请使用LEFT JOIN
。
此索引(包含任何顺序的列)可能有助于提高性能:
INDEX(gender, visible, active, completed, approved)
因此...
SELECT a.userid,
p.name,
p.attractive,
IF(a.domain="domain.com", 1,2) AS preferredDomain,
IF(a.domain LIKE "%domain.com", 1,2) AS preferredSubDomain
FROM users AS a
LEFT JOIN photos AS p
ON ( p.userid = a.userid
AND p.type = 'profile' )
WHERE a.gender = 1
AND a.visible = 1
AND a.active = 1
AND a.completed = 1
AND a.approved = 1
AND p.name IS NOT NULL
ORDER BY preferredDomain ASC, p.attractive DESC, a.lastlogin DESC,
preferredSubDomain ASC
LIMIT 100;
我仍然不确定name
和LEFT
是否得到正确处理。