这对我来说是一个相当令人困惑的问题。我有一个充满棒球统计数据的数据库。运行此查询:
SELECT * FROM hits
JOIN stadiums ON stadiums.gameName = hits.gameName
JOIN players ON (players.gameName = hits.gameName AND players.id = hits.batter)
JOIN games ON games.gameName = hits.gameName
WHERE games.type = 'R'
LIMIT 50
Run Code Online (Sandbox Code Playgroud)
返回:
/* 0 rows affected, 50 rows found. Duration for 1 query: 0.218 sec. */
Run Code Online (Sandbox Code Playgroud)
但是运行这个查询:
SELECT * FROM hits
JOIN stadiums ON stadiums.gameName = hits.gameName
JOIN players ON (players.gameName = hits.gameName AND players.id = hits.batter)
JOIN games ON games.gameName = hits.gameName
WHERE games.leagueLevel = 'mlb'
LIMIT 50
Run Code Online (Sandbox Code Playgroud)
挂了很长时间。游戏表上的索引只有 games.gameName 而没有别的。
SELECT DISTINCT type FROM games给出8个单字符行(VARCHAR 1),包括一个NULL。
SELECT DISTINCT LeagueLevel FROM games 给出 6 个三字符行 (VARCHAR 5),包括一个 NULL。
我不知道为什么第二个查询会异常缓慢,而第一个查询运行得很好。
谢谢你的帮助。
观点#1:您需要查看列值人口
SELECT COUNT(1) rowount,type FROM games GROUP BY type WITH ROLLUP;
SELECT COUNT(1) rowcount,leaguelevel FROM games GROUP BY leaguelevel WITH ROLLUP;
Run Code Online (Sandbox Code Playgroud)
从你的问题中,我总结出两点:
观点#2:您可能需要重构此查询
请注意,查询将在所有 JOIN 完成后执行 WHERE 部分。如果可以更早地执行 WHERE 部分,则可以帮助减少时间。尝试像这样重新组织查询:
SELECT * FROM hits
JOIN stadiums ON stadiums.gameName = hits.gameName
JOIN players ON (players.gameName = hits.gameName AND players.id = hits.batter)
JOIN (SELECT * FROM games WHERE leagueLevel = 'mlb') games
ON games.gameName = hits.gameName
LIMIT 50;
Run Code Online (Sandbox Code Playgroud)
观点#3:只检索你真正需要的列
我看到你有 SELECT * 并且你有四张桌子(命中、体育场、球员、比赛)。您将有大量重复数据拖入查询中,尤其是在从所有四个表中拖出 gameName 列时。
您应该重新组织查询以仅引入一个 gameName 列:
SELECT hits.gameName,hits.*,players.*,staduims.*,games.* FROM hits
JOIN stadiums ON stadiums.gameName = hits.gameName
JOIN players ON (players.gameName = hits.gameName AND players.id = hits.batter)
JOIN (SELECT * FROM games WHERE leagueLevel = 'mlb') games
ON games.gameName = hits.gameName
LIMIT 50;
Run Code Online (Sandbox Code Playgroud)
此外,如果您不需要命中表中的每一列,则只包含您知道将访问的列。球员、体育场和比赛也是如此。
换句话说,例如,如果您只需要播放器表中的 playerName,那么您不需要在 SELECT 中使用 player.*。您只需要 player.playerName。
观点#4:您可能需要索引 LeagueLevel 列
您需要执行以下操作来制作所需的索引:
ALTER TABLE games ADD INDEX (leagueLevel);
Run Code Online (Sandbox Code Playgroud)
在这样做之前,运行这个
SELECT COUNT(1) rowcount,leaguelevel FROM games GROUP BY leaguelevel WITH ROLLUP;
Run Code Online (Sandbox Code Playgroud)
任何数量大于表的 5% 的 LeagueLevel 值都会导致 MySQL 查询优化器不使用索引。
| 归档时间: |
|
| 查看次数: |
1572 次 |
| 最近记录: |