我开发了一个网站,两个团队可以互相面对面。第一个团队为某个m
(堆栈)创建匹配搜索value
,status
=搜索。第一个团队具有elo
(级别)属性。
当第二个团队(elo为150)将搜索匹配时,我们执行以下查询:
SELECT m.id, m.value, m.teamOneScore, m.teamTwoScore, m.date, m.status, m.detail, m.team_one_id, m.team_two_id
FROM user_match m
INNER JOIN team t ON m.team_one_id = t.id
WHERE t.id = m.team_one_id
AND t.id <> 3 // You don't want to play against your own team
AND t.elo <= 200 // 50 of elo range for example
AND t.elo >= 100
AND m.value = '0.5'
AND m.status = 'search'
LIMIT 1
问题是这个查询很长,即使我们只有15000 user_match(只有40行符合要求,值= 0.5,状态=搜索)和15000个团队(有5570个团队可以满足要求与elo和id)
我尝试EXPLAIN
请求,结果如下:
如果用户在搜索匹配项时没有对手,请求可能需要3分钟,并且当多次执行相同的请求时,此时间将减少(缓存?),如果有对手则更快
我可以准确的最后一件事是user_match表包含一个detail
属性,只有匹配状态=结束时才包含重json_array
你知道这是否是正常的执行时间?我该怎么做才能改善这一点?
谢谢!
答案 0 :(得分:2)
直截了当,您需要使用where子句索引列。
根据解释,似乎mysql计划仅使用pk作为索引。并且你的pk在哪里使用列来排除只有单行。因此,mysql将扫描除单行之外的所有表。
在这种情况下,您必须索引elo列以使查询计划扫描最少的行。
ALTER TABLE team ADD INDEX search(id, elo);
然后查看查询时间。
+ EDIT 看起来上面的解决方案并没有太多改善查询时间。
这是另一点。您需要在join子句中首先放置较小的范围表。使用上面的索引,团队表将更小。因此查询将如下所示。
SELECT m.id, m.value, m.teamOneScore, m.teamTwoScore, m.date,
m.status, m.detail, m.team_one_id, m.team_two_id
FROM team t
INNER JOIN user_match m ON m.team_one_id = t.id
WHERE
t.elo <= 200 // 50 of elo range for example
AND t.elo >= 100
AND t.id <> 3 // You don't want to play against your own team
AND m.value = '0.5'
AND m.status = 'search'
LIMIT 1
让我看看这是否适合你
答案 1 :(得分:1)
首先,不要在t.id = m.team_one_id
上重复这个条件。所以,这是您的查询:
SELECT m.id, m.value, m.teamOneScore, m.teamTwoScore, m.date, m.status, m.detail, m.team_one_id, m.team_two_id
FROM user_match m INNER JOIN
team t
ON m.team_one_id = t.id
WHERE t.id <> 3 AND // You don't want to play against your own team
t.elo <= 200 AND // 50 of elo range for example
t.elo >= 100 AND
m.value = '0.5' AND
m.status = 'search'
LIMIT 1;
其次,该查询看起来很可疑,因为您LIMIT
没有ORDER BY
。通常,您需要ORDER BY
,因此您返回的行在每次执行时都保证相同。
索引是您加快查询速度的方法。我将从以下索引开始:
user_match(status, value, team_one_id)
team(id, elo)
基于user_match
子句,where
上的索引对于该表是最佳的。注意:如果value
是一个数字,则不要在0.5
周围使用单引号,这会使优化程序混淆。
如果team
被声明为主键,则id
上的第二个索引不是必需的。
答案 2 :(得分:0)
我认为您可以尝试为主要查询的列提供索引,例如列currently present in where condition.
..
如果它们没有编入索引,那么你可以尝试'alter query将索引添加到列',然后查看响应时间。
答案 3 :(得分:0)
为什么在join子句中使用where子句时需要t.id = m.team_one_id(INNER JOIN team t ON m.team_one_id = t.id)?我相信这是多余的。
我认为你应该在ON子句中移动团队过滤器并获得类似这样的东西
SELECT m.id, m.value, m.teamOneScore, m.teamTwoScore, m.date, m.status, m.detail, m.team_one_id, m.team_two_id
FROM user_match m
INNER JOIN team t ON m.team_one_id = t.id and t.id <> 3 and t.elo <= 200 and t.elo >= 100
WHERE m.value = '0.5'
AND m.status = 'search'
LIMIT 1
然后在user_match表的值和状态列中添加复合索引。
ALTER TABLE user_match ADD INDEX usermatchteam_idx(value, status);
以及上面评论中提到的团队表索引
ALTER TABLE team ADD INDEX elosearch_idx(id, elo);
请尝试这种方法。 如果这没有帮助,请为team和user_match表提供创建表,以便我们进一步调查。