2017-03-03 79 views
0

我有一个约400k行的用户表,需要检索其中一些(最多100),同时与其他表进行多个JOINS。 (使用mysql)如何优化这个慢sql查询?

我的问题是,查询目前有约800ms的执行时间(取46ms)。我的目标是优化查询以减少执行时间。

我的初始查询看起来是这样的:

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) 

想想需要连接的行数会大大减少,因此会缩短执行时间。这种改变似乎有所帮助,但查询仍然太低。

有人可以看到执行缓慢的一些其他原因吗?

+2

似乎是一个合理的响应时间... – jarlh

+1

查询似乎固定,建议索引改进... – JohnHC

回答

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) 

这取决于其whittles下来的数据更多。我的猜测是last_active更重要。还要注意,前三个键可以按任意顺序排列,只要它们是前三个。

这可能有帮助,但我怀疑你会看到一个惊人的进步。

+0

感谢acutally确实有点帮助:) –

+0

快多少? –

+0

100-200毫秒更快 –