【问题标题】:SQL LEFT JOIN Query not using Primary Keys is too slow, how can I speed up?SQL LEFT JOIN Query not using Primary Keys 太慢了,如何加快速度?
【发布时间】:2019-03-08 02:33:10
【问题描述】:

我有三个 MySQL 表; “teams”和两个表,具体取决于团队类型(“team_type_1”和“team_type_2”)。我需要将所有三个表查询到一个表中,并将每个团队从两个 team_type 表中的英里数加到一个“英里”列中。

下面的查询可以根据需要运行,但由于我的 JOIN 查询没有使用主 ID,因此它要么被锁定,要么花费的时间太长。

在 JOIN 中使用主 ID“team_type_1.id”和“team_type_2.id”会很好,但我在下面最后一个查询中的尝试仍在内部查询中使用非主键。我可以采取其他方法来加快查询速度吗?

Table 1: teams (3000 total records)
id (primary) | team_name


Table 2: team_type_1 (12000 total records)
id (primary) | team_id | miles


Table 3: team_type_2 (150000 total records)
id (primary) | team_id | miles

将以上表格组合成: 团队名称 |里程


当使用主键单独运行这些查询时,只需要几毫秒,但我需要将这些表组合起来:

SELECT
teams.team_name,
SUM(team_type_1.miles)
FROM team_type_1
LEFT JOIN teams ON teams.id = team_type_1.team_id
GROUP BY team_type_1.team_id


SELECT
teams.team_name,
SUM(team_type_2.miles)
FROM team_type_2
LEFT JOIN teams ON teams.id = team_type_2.team_id
GROUP BY team_type_2.team_id

当组合时,不使用主键,它会锁定数据库:

SELECT
teams.team_name,
SUM(CASE WHEN team_type_2.miles THEN team_type_2.miles ELSE team_type_1.miles END)
FROM teams

LEFT JOIN team_type_1 ON team_type_1.team_id = teams.id
LEFT JOIN team_type_2 ON team_type_2.team_id = teams.id

GROUP BY teams.id

这大约需要 8-10 秒才能运行,但内部选择使用的是非主 ID;有没有办法加快速度?

SELECT
teams.team_name,
SUM(CASE WHEN team_type_2.miles THEN team_type_2.miles ELSE team_type_1.miles END)
FROM teams

LEFT JOIN team_type_1 ON team_type_1.id = (SELECT team_type_1.id FROM team_type_1 WHERE team_type_1.team_id = teams.id GROUP BY team_type_1.team_id)
LEFT JOIN team_type_2 ON team_type_2.id = (SELECT team_type_2.id FROM team_type_2 WHERE team_type_2.team_id = teams.id GROUP BY team_type_2.team_id)

WHERE team_type_2.miles > 0 OR team_type_1.miles > 0 GROUP BY teams.id

  • 更新:

感谢@Strawberry 的 UNION 提示,除了上面的几列和三个表之外,我还有其他要查询的表和列,但由于我能够使用主 ID,所以没有提及这些对于那些。下面是我使用 UNIONS 的完整查询结构,它可以按我的需要工作。

SELECT
teams.team_name,
teams.start_date,
team_counties.county_name,
team_leagues.league_name,
SUM(team_type_1.miles)
FROM team_type_1

LEFT JOIN teams ON teams.id = team_type_1.team_id
LEFT JOIN team_counties ON team_counties.id = teams.county_id
LEFT JOIN team_leagues ON team_leagues.id = teams.league_id

GROUP BY team_type_1.team_id

UNION

SELECT
teams.team_name,
teams.start_date,
team_counties.county_name,
team_leagues.league_name,
SUM(team_type_2.miles)
FROM team_type_2

LEFT JOIN teams ON teams.id = team_type_2.team_id
LEFT JOIN team_counties ON team_counties.id = teams.county_id
LEFT JOIN team_leagues ON team_leagues.id = teams.league_id

GROUP BY team_type_2.team_id

【问题讨论】:

  • 我不明白您为什么要加入而不是合并这两个查询。见meta.stackoverflow.com/questions/333952/…
  • @Strawberry 啊,我与 UNIONS 合作了很长时间,但我也将其他表与其他列一起加入并不断收到“列不匹配”类型的错误。但是,您给了我一个想法,我在上面使用 UNIONS 发布了一个更新,它看起来可以按我的需要工作,而且速度非常快。感谢您的提示。

标签: php mysql join union


【解决方案1】:

有几种方法可以解决这个问题,但最简单的解决方案是在两个子表中简单地 index team_id 列:

ALTER TABLE `team_type_1`
    ADD INDEX `team_id` (`team_id`);
ALTER TABLE `team_type_2`
    ADD INDEX `team_id` (`team_id`);

这应该允许您以一定的速度执行以下操作:

SELECT teams.id,
       teams.team_name,
       SUM(IFNULL(team_type_1.miles, 0) + IFNULL(team_type_2.miles, 0)) sum_miles
FROM teams
LEFT JOIN team_type_1 ON team_type_1.team_id = teams.id
LEFT JOIN team_type_2 ON team_type_2.team_id = teams.id
GROUP BY teams.id,
         teams.team_name

【讨论】:

  • 谢谢,但很抱歉,miles 是填充这些列的计算表单字段并且是文本类型,无法将它们作为索引来测试您的建议。
【解决方案2】:

我有同样的问题。就我而言,我将列(非主列)从非唯一索引更改为唯一索引。它使我的查询速度提高了 3 倍。希望,它可以帮助某人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-23
    • 2011-03-16
    • 1970-01-01
    • 2019-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-24
    相关资源
    最近更新 更多