MySQL很长查询,内连接

时间:2018-02-24 11:24:41

标签: mysql sql join inner-join

我开发了一个网站,两个团队可以互相面对面。第一个团队为某个m(堆栈)创建匹配搜索valuestatus =搜索。第一个团队具有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请求,结果如下:

enter image description here

如果用户在搜索匹配项时没有对手,请求可能需要3分钟,并且当多次执行相同的请求时,此时间将减少(缓存?),如果有对手则更快

我可以准确的最后一件事是user_match表包含一个detail属性,只有匹配状态=结束时才包含重json_array

你知道这是否是正常的执行时间?我该怎么做才能改善这一点?

谢谢!

4 个答案:

答案 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表提供创建表,以便我们进一步调查。