Как я могу исправить ошибку MySql LEFT JOIN с помощью буфера соединения (блочный вложенный L oop)? - PullRequest
0 голосов
/ 27 апреля 2020

Я думаю, что столкнулся с этой MySql ошибкой , но решение ссылается на комментарий, который больше не существует. Кто-нибудь знает, каково решение?

Мой конкретный пример использования - игра с раундами. Я хочу найти все (игровые, круглые) пары, в которых после события «Действие» нет событий «Бездействие». Это мой запрос:

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).

Ответы [ 2 ]

2 голосов
/ 27 апреля 2020

Я думаю, что вы можете делать то, что хотите, с помощью одного агрегатного запроса, используя для фильтрации условие 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
    )

0 голосов
/ 30 апреля 2020

План 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)

(я предполагаю, что id - это PRIMARY KEY из event.)

...