Левое соединение работает намного быстрее внутреннего соединения - PullRequest
1 голос
/ 20 апреля 2019

Я пытался оптимизировать производительность запроса, который мне удалось сделать массово. При использовании левого соединения оно сократилось с 36,7 до 3,3 секунды, но я не совсем понимаю, почему левое соединение дает мне такой скачок производительности по сравнению с обычным соединением.

Набор результатов, выкупленный обоими запросами, идентичен.

Вот запросы с EXPLAIN ...

Обычное соединение: 36,7 секунд

SELECT t1.entityId, SUM(t2.gbp) AS amount
FROM transactionsV2 t1
JOIN
(
    SELECT
    t.uniqueId,
    ROUND((CASE WHEN t.currency != "GBP" THEN t.amount/er.exchange_rate ELSE t.amount END), 2) AS gbp
    FROM transactionsV2 t
    JOIN total_control.exchange_rates er 
    ON t.currency = er.currency
    ) t2
ON t1.uniqueId = t2.uniqueId
WHERE t1.paymentType IN ("DB", "3D")
AND t1.processing_time >= '2019-04-01 00:00:00'
AND t1.processing_time <= '2019-04-20 23:59:59'
AND t1.status = 1
GROUP BY t1.entityId

enter image description here

Слева: 3,3 секунды

SELECT t1.entityId, SUM(t2.gbp) AS amount
FROM transactionsV2 t1
LEFT JOIN
(
    SELECT
    t.uniqueId,
    ROUND((CASE WHEN t.currency != "GBP" THEN t.amount/er.exchange_rate ELSE t.amount END), 2) AS gbp
    FROM transactionsV2 t
    JOIN total_control.exchange_rates er 
    ON t.currency = er.currency
    ) t2
ON t1.uniqueId = t2.uniqueId
WHERE t1.paymentType IN ("DB", "3D")
AND t1.processing_time >= '2019-04-01 00:00:00'
AND t1.processing_time <= '2019-04-20 23:59:59'
AND t1.status = 1
GROUP BY t1.entityId

enter image description here

Ответы [ 3 ]

0 голосов
/ 21 апреля 2019

Хотя я не могу объяснить, почему он делает то, что делает ... Я не знаю, почему вы присоединяетесь, когда все транзакции происходят из таблицы TransactionsV2.Внутреннее левое соединение вытягивает ВСЕ транзакции, присоединенные к обменному курсу, но не применяется, применяя все транзакции.Затем присоединение к внешнему экземпляру на конкретную дату.

Из того, что я вижу, ваша таблица TransactionV2 имеет такую ​​структуру:вычисление обменного курса сделано, но все же в конечном итоге сгруппировано по сущности ... Я бы попробовал что-то вроде.

SELECT
        t1.EntityID,
        SUM( ROUND(CASE WHEN t1.currency != "GBP" 
                        THEN t.amount/er.exchange_rate 
                        ELSE t.amount END, 2) ) Amount
    from
        TransactionsV2 t1
            LEFT JOIN total_control.exchange_rates er 
                ON t1.currency = er.currency
    WHERE 
            t1.paymentType IN ("DB", "3D")
        AND t1.processing_time >= '2019-04-01 00:00:00'
        AND t1.processing_time <= '2019-04-20 23:59:59'
        AND t1.status = 1
    GROUP BY 
        t1.entityId

Он проходит записи раз и только для критериев.Я изменил объединение, чтобы обменять курсы на LEFT-JOIN в случае отсутствия записи - так как я не знаю точных условий, которые могут (или нет) совпадать. Может быть, это ваше значение! = "GBP" в этом случае/when.

Чтобы обеспечить некоторую оптимизацию и количество транзакций, я бы построил составной индекс для вашей таблицы транзакций на

( Status, Processing_Time, PaymentType, EntityID )
0 голосов
/ 21 апреля 2019

Я полагаю, что производительность отличается из-за разных способов объединения таблиц, которые используются INNER JOIN (JOIN) и LEFT JOIN, и их влияния на индексы.

Для первого взгляда на заказ в EXPLAIN. Вы можете видеть, что LEFT JOIN объединит таблицы в фиксированном порядке (слева направо). INNER JOIN - оптимизатор создаст для вас порядок соединения (сначала маленький стол). Для обоих случаев key для таблицы t1 (в списке EXPLAIN) отличается.

Это всегда зависит от структуры ваших таблиц, будет ли индекс (правильный индекс) применен или нет, когда другой порядок соединения. Это может зависеть даже, например, от разных сопоставлений таблиц.

Посмотрите на это, я надеюсь, что это даст результат.

0 голосов
/ 21 апреля 2019

Можете ли вы выразить это как коррелированный подзапрос?

SELECT t.entityId,
       (SELECT  SUM(CASE WHEN t2.currency <> 'GBP' THEN t2.amount/er.exchange_rate ELSE t.amount END)j
SUM(t2.gbp) AS amount
        FROM transactionsV2 t2 JOIN
             total_control.exchange_rates er 
             ON t.currency = er.currency
        WHERE t2.uniqueid = t.uniqueid
FROM transactionsV2 t
WHERE t.paymentType IN ('DB', '3D') AND
      t.processing_time >= '2019-04-01' AND
      t.processing_time < '2019-04-21' AND
      t.status = 1;

Если это так, вы можете добавить индексы в базовые таблицы для повышения производительности. Однако я подозреваю, что таблица транзакций действительно является представлением.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...