【问题标题】:Left join running much faster than inner join左连接比内连接运行得快得多
【发布时间】:2019-09-10 15:07:52
【问题描述】:

我一直在尝试优化我已经成功完成的查询的性能。使用左连接的时间从 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

左加入: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

【问题讨论】:

  • 你一个接一个地执行了这两个查询? ...尝试反转序列..
  • 我试过了,但结果还是一样。我也在不同的浏览器中运行了查询,所以不要认为这与缓存有任何关系。
  • 还是一样的@RaymondNijland。这不是缓存问题。
  • 好吧,在不知道表结构和索引的情况下,我们不会解决这个问题,那肯定我已经尝试过一个合乎逻辑的答案。你应该在不关闭输出的情况下编辑问题SHOW CREATE TABLE transactionsV2跨度>
  • 样本数据和期望的结果真的很有帮助——就像描述查询应该做什么一样。

标签: mysql sql


【解决方案1】:

你能把它表达为一个相关的子查询吗?

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;

如果是这样,您可以向基础表添加索引以提高性能。但是,我怀疑事务表确实是一个视图。

【讨论】:

    【解决方案2】:

    虽然我无法解释为什么它正在做它正在做的事情......我不知道为什么当所有事务都来自 TransactionsV2 表时你是自加入的。内部左连接正在拉动所有加入汇率的交易,但没有应用任何地方,因此拉动了所有交易。然后在特定日期加入外部实例。

    据我所见,您的 TransactionV2 表的结构类似于...

    UniqueID auto-increment
    EntityID (such as multiple transactions for this one person/company/entity)
    Amount (based on relation to exchange rate and transaction amount)
    

    因此,您将外部的每个唯一 ID 转换为内部的唯一 ID 一旦汇率计算完成,但最终仍按实体分组...... 我会尝试类似的东西。

    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" 值/何时。

    为了帮助确保一些优化和交易量,我将在您的交易表上建立一个复合索引

    ( Status, Processing_Time, PaymentType, EntityID )
    

    【讨论】:

    • 嗨@DRapp,您的查询执行速度比我的稍快,3.1 秒而不是 3.3 秒,这很棒。查看我的查询,您完全正确。自加入是完全没有必要的。我仍然不明白的是,使用左连接到 exchange_rates 表,查询在 3.1 秒内执行,但使用内连接,需要 12 秒,但结果集是相同的。为什么使用内连接而不是左连接时会出现这样的性能损失?
    • @Dally,抱歉,无法回答速度差异的原因,但仅供参考,我发现 MySQL 有一个关键字“STRAIGHT_JOIN”,它告诉引擎按照我给你的顺序运行。我有一个查询在 24 小时后使用父表和 20 多个子查找表失败。添加了 straight_join,查询不到 2 小时就完成了。数据超过 2300 万行。谁知道呢,但总有一天也会对你有所帮助。
    【解决方案3】:

    我猜性能是不同的,因为INNER JOIN (JOIN)LEFT JOIN 使用的表连接方式及其对索引的影响不同。

    首先查看EXPLAIN 中的顺序。 您可以看到LEFT JOIN 将以固定顺序(从左到右)连接表。 INNER JOIN - 优化器将为您构建连接顺序(首先是小表)。 对于这两种情况,keyt1(在 EXPLAIN 列表中)是不同的。

    当连接顺序不同时,是否应用索引(正确索引)总是取决于表的结构。例如,它甚至可以依赖于不同的表排序规则。

    这样看,希望会有结果。

    【讨论】:

    • 可以肯定地说,在大多数情况下,左连接会优于内连接吗?我知道 2 个不同的连接做不同的事情并产生不同的结果,但如果你知道自己在做什么,你可以从内部和左连接产生相同的结果,但左连接总是更快吗?
    • 不,理论上 INNER JOIN 更快。这取决于您的任务......对于不同的事物,不同的 JOIN 是不同的。您应该选择最适合您的任务并产生高性能的结果。
    • 在我的例子中,我认为内部连接会更合适,但它显然不适合性能。
    猜你喜欢
    • 2011-12-11
    • 2018-03-06
    • 2017-06-17
    • 1970-01-01
    • 2014-06-14
    • 1970-01-01
    • 2015-02-03
    • 2012-01-03
    • 1970-01-01
    相关资源
    最近更新 更多