[英]MySQL very long query, inner join
我開發了一個網站,兩個團隊可以互相面對面。 第一個團隊為某個value
(堆棧)創建匹配搜索m
, 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
你知道這是正常的執行時間嗎? 我該怎么做才能改善這一點?
謝謝 !
直截了當,您需要使用where子句索引列。
據解釋,似乎mysql計划只使用pk作為索引。 並且你的pk在哪里使用列來排除只有單行。 因此,mysql將掃描除單行之外的所有表。
在這種情況下,您必須索引elo列以使查詢計划掃描最少的行。
ALTER TABLE team ADD INDEX search(id, elo);
然后查看查詢時間。
+編輯它似乎上面的解決方案並沒有多少提高查詢時間。
這是另一點。 您需要在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
讓我看看這是否適合你
首先,不要在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
周圍使用單引號,這可能會使優化器混淆。
如果將id
聲明為主鍵,則不需要team
的第二個索引。
我認為您可以嘗試通過為主要查詢的列提供索引,就像列currently present in where condition.
..
如果它們沒有編入索引,那么你可以嘗試“更改查詢以向列添加索引”,然后查看響應時間。
當你在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表的value和status列上添加復合索引。
ALTER TABLE user_match ADD INDEX usermatchteam_idx(value, status);
和上面評論中提到的團隊表索引
ALTER TABLE team ADD INDEX elosearch_idx(id, elo);
請嘗試這種方法。 如果這沒有幫助,請為team和user_match表提供創建表,以便我們進一步調查。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.