【问题标题】:How do I fix MySql's LEFT JOIN Using join buffer (Block Nested Loop) Bug?如何使用连接缓冲区(块嵌套循环)修复 MySql 的 LEFT JOIN 错误?
【发布时间】:2020-04-27 20:01:30
【问题描述】:

我想我遇到了this MySql bug,但解决方案引用了一个不再存在的评论。有谁知道解决方案是什么?

我的特定用例涉及带有回合的游戏。我想找到在“动作”事件之后没有“不作为”事件的所有(游戏、回合)对。这是我的查询:

SELECT
    *
FROM
    (
        SELECT
            MAX(id) AS id,
            game_id,
            round
        FROM event
        WHERE
            type_of="Action"
        GROUP BY
            game_id, round
    ) AS last_action
    LEFT JOIN (
        SELECT
            MAX(id) AS id,
            game_id,
            round
        FROM event
        WHERE
            type_of="Inaction"
        GROUP BY
            game_id, round                  
    ) AS last_inaction
        USING
            (game_id, round)
WHERE
    last_inaction.id IS NULL
    OR last_action.id > last_inaction.id;

这运行非常缓慢并且有一个包含Using where; Using join buffer (Block Nested Loop) 的解释。但是,如果我将查询的 WHERE 语句编辑为功能等效的

WHERE
    last_inaction.id IS NULL
    OR last_action.id > last_inaction.id + 0;

查询几乎立即执行,不包括Using where; Using join buffer (Block Nested Loop)

【问题讨论】:

  • 请提供SHOW CREATE TABLE

标签: mysql sql database left-join query-optimization


【解决方案1】:

我认为您可以使用单个聚合查询执行您想要的操作,使用 HAVING 子句进行过滤:

SELECT game_id, round
FROM event
WHERE type_of IN ('Action', 'Inaction')
GROUP BY game_id, round
HAVING
    MAX(CASE WHEN type_of = 'Inaction' THEN id END) 
        < MAX(CASE WHEN type_of = 'Action' THEN id END)
    OR (
        MAX(CASE WHEN type_of = 'Inaction' THEN id END) IS NULL
        AND MAX(CASE WHEN type_of = 'Action' THEN id END) IS NOT NULL
    )

【讨论】:

  • 这几乎行得通!在检查 Inaction 是否为 null 时,您还必须检查 Action 是否为 null。我已提交修改请求。
  • 我不确定是否应该标记这个最佳答案。 GMB 解决了我的用例,但没有回答更大的问题。
  • @trexinf14s:好的,我明白了。我相应地编辑了我的答案 - 我还添加了一个 WHERE 原因,这可能会使查询更有效率。
【解决方案2】:

方案 A:将 block_nested_loop=OFF 设置为 optimizer_switch

B 计划:简化查询并加快查询速度:

SELECT  b.game_id, b.round
    FROM  
        ( SELECT  MAX(id) AS id
            FROM  event
            WHERE  type_of IN ('Action', 'Inaction')
            GROUP BY  game_id, round 
        ) AS a
    JOIN  event b USING(id)
    WHERE  b.type_of = 'Action';

(我的版本提供的列较少,但其余的似乎是多余的或不相关的。)

并添加复合索引:

INDEX(game_id, round, type_of, id)

(我假设ideventPRIMARY KEY。)

【讨论】:

    猜你喜欢
    • 2016-03-26
    • 2019-10-17
    • 2020-05-20
    • 2020-07-12
    • 2015-04-28
    • 1970-01-01
    • 2018-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多