我有一个大约有400k行的用户表,需要在与其他表进行多个JOINS时检索其中一些(最多100个)。 (使用mysql)
我的问题是查询当前的执行时间大约为800毫秒(取46毫秒)。我的目标是优化查询以减少执行时间。
我的初始查询如下所示:
SELECT iduser, imageurl, birthdate, active, last_active, created, gender_idgender, orientation_idorientation, region_idregion, moji.moji_idmoji as moji_idmoji, status.value as status, requests.value as requestsRecv, requestssent.value as requestsSent, username.value as username, likecount.value as likeCount, reportcount.value as reportCount
FROM user u
JOIN user_has_moji moji ON ( u.iduser = moji.user_iduser )
JOIN user_has_data status ON ( u.iduser = status.user_iduser AND status.datatype_iddatatype = 1 )
JOIN user_has_data requests ON ( u.iduser = requests.user_iduser AND requests.datatype_iddatatype = 3 )
JOIN user_has_data requestssent ON ( u.iduser = requestssent.user_iduser AND requestssent.datatype_iddatatype = 4 )
JOIN user_has_data username ON ( u.iduser = username.user_iduser AND username.datatype_iddatatype = 5 )
JOIN user_has_data likecount ON ( u.iduser = likecount.user_iduser AND likecount.datatype_iddatatype = 6 )
JOIN user_has_data reportcount ON ( u.iduser = reportcount.user_iduser AND reportcount.datatype_iddatatype = 7 )
WHERE banned = 0 AND active = 1 AND u.reviewstatus_idreviewstatus = 3 AND DATEDIFF(last_active,'2017-03-03 10:06:36') >=0 AND DATEDIFF(birthdate, '1999-03-03 15:06:36') >= 0 AND DATEDIFF(birthdate, '1967-03-03 15:06:36') <= 0 ORDER BY last_active DESC LIMIT 100
我认为执行时间长的原因是它必须在执行查询之前将整个用户表与其他表一起加入,因此我尝试了这种方法:
SELECT iduser, imageurl, birthdate, active, last_active, created, gender_idgender, orientation_idorientation, region_idregion, moji.moji_idmoji as moji_idmoji, status.value as status, requests.value as requestsRecv, requestssent.value as requestsSent, username.value as username, likecount.value as likeCount, reportcount.value as reportCount
FROM ( SELECT * FROM user WHERE banned = 0 AND active = 1 AND reviewstatus_idreviewstatus = 3 AND DATEDIFF(last_active,'2017-03-03 10:01:30') >=0 AND DATEDIFF(birthdate, '1999-03-03 15:01:30') >= 0 AND DATEDIFF(birthdate, '1967-03-03 15:01:30') <= 0 ORDER BY last_active DESC LIMIT 100 ) as u
JOIN user_has_moji moji ON ( u.iduser = moji.user_iduser )
JOIN user_has_data status ON ( u.iduser = status.user_iduser AND status.datatype_iddatatype = 1 )
JOIN user_has_data requests ON ( u.iduser = requests.user_iduser AND requests.datatype_iddatatype = 3 )
JOIN user_has_data requestssent ON ( u.iduser = requestssent.user_iduser AND requestssent.datatype_iddatatype = 4 )
JOIN user_has_data username ON ( u.iduser = username.user_iduser AND username.datatype_iddatatype = 5 )
JOIN user_has_data likecount ON ( u.iduser = likecount.user_iduser AND likecount.datatype_iddatatype = 6 )
JOIN user_has_data reportcount ON ( u.iduser = reportcount.user_iduser AND reportcount.datatype_iddatatype = 7 )
认为需要加入的行数会大大减少,从而缩短执行时间。这种变化似乎有所帮助,但查询仍然太低。
有人可以看到执行缓慢的其他原因吗?
答案 0 :(得分:3)
您的响应时间非常合理,因此您的表格似乎已正确编入索引。但是,让我们看一下WHERE
子句(我添加了假定的表别名):
WHERE u.banned = 0 AND u.active = 1 AND
u.reviewstatus_idreviewstatus = 3 AND
DATEDIFF(u.last_active,'2017-03-03 10:06:36') >=0 AND
DATEDIFF(u.birthdate, '1999-03-03 15:06:36') >= 0 AND
DATEDIFF(u.birthdate, '1967-03-03 15:06:36') <= 0
首先,删除datediff()
并进行简单比较。我想你想要这个:
WHERE u.banned = 0 AND u.active = 1 AND
u.reviewstatus_idreviewstatus = 3 AND
u.last_active >= '2017-03-03 10:06:36' AND
u.birthdate >= '1999-03-03 15:06:36' AND
u.birthdate <= '1967-03-03 15:06:36'
我对最后三个条件有点怀疑,但使用datediff()
令人困惑。这就是简单比较更好的原因之一。
您需要快速找到这些行,这表明两个索引之一:
users(banned, active, reviewstatus_idreviewstatus, last_active, birthdate)
或
users(banned, active, reviewstatus_idreviewstatus, birthdate, last_active)
这取决于更多地减少数据。我的猜测是last_active
更重要。另请注意,前三个键可以按任意顺序排列,只要它们是前三个。
这可能有所帮助,但我怀疑你会看到一个惊人的改进。