【问题标题】:MySQL JOIN and SUM performance issueMySQL JOIN 和 SUM 性能问题
【发布时间】:2016-12-12 10:43:47
【问题描述】:

我遇到了 MySQL JOIN 和 SUM 的问题。因为我的 JOIN 有多个匹配项,所以我会在 JOIN 中执行一个 SELECT,所以它的总和不会太多。

问题:
我的查询非常慢。在下面的测试设置中,它仅在 1ms 内运行,没有任何索引。但在我的生产数据库中,当仅选择一条记录 (WHERE id = X) 时,此查询大约需要 4 秒。

表 a 有 ~700.000 条记录
表 b 有约 800.000 条记录
表 c 有 ~45.000 条记录

表 a 的索引位于 id
表 b 在ida_id 上有索引
表 c 在 ida_id 上有索引

下面是简化的表格和使用的查询。

a

id
---
1

b

id | a_id | amount | price
--------------------------
 1 |    1 |      1 |    25
 2 |    1 |      1 |    20

c

id | a_id | amount | price
--------------------------
 1 |    1 |      1 |    23
 2 |    1 |      1 |    20

查询:
现在,当我运行此查询以获取在表 a 中有引用的 bc 的总和时。

SELECT id, bPrice, cPrice
FROM a
LEFT JOIN (SELECT a_id, SUM(amount * price) AS bPrice FROM b GROUP BY a_id) bb ON a.id = bb.a_id
LEFT JOIN (SELECT a_id, SUM(amount * price) AS cPrice FROM c GROUP BY a_id) cc ON a.id = cc.a_id

错误的结果,但速度很快

SELECT 
    a.id,
    SUM(b.amount * b.price) AS bPrice,
    SUM(c.amount * c.price) AS cPrice
FROM a
JOIN b ON a.id = b.a_id
JOIN c ON a.id = c.a_id;

SQL Fiddle example

【问题讨论】:

  • bc 中的a_id 上没有索引?

标签: mysql join


【解决方案1】:

MySQL 将难以从子查询中提取索引以进行连接,并怀疑您正在从子查询中连接很多行。

作为第一步,您可以尝试删除其中一个子查询,将其更改为与主表的联接。

SELECT id, 
        SUM(b.amount * b.price) AS bPrice, 
        cPrice
FROM a
LEFT OUTER JOIN b ON a.id = b.a_id
LEFT OUTER JOIN 
(
    SELECT a_id, 
            SUM(amount * price) AS cPrice 
    FROM c 
    GROUP BY a_id
) cc ON a.id = cc.a_id
GROUP BY a.id,
        cc.cPrice

【讨论】:

  • 此查询失败,见最后一行cc.cPrice
  • 遗漏了一个逗号。现在修复它
  • 好的,当我还添加一个WHERE a.id = '' 时,它会在大约 80 毫秒内运行。当我在整个数据库中运行 80 万条记录时,它会在大约 9 秒内运行。对于所有 800k 记录,这是可以接受的,对于单个记录,80ms 也是可以接受的,来自 4000ms! Tnx!
  • @Timo002 - 你能确认你的索引吗?您的问题是 Table b 在 id, a_id 上有索引,但这与 SQL Fiddle 不匹配。如果它是覆盖两列的单个索引,那么它对子查询没有多大帮助,但如果它是 2 个单独的索引,它可能会有所帮助。
  • SQL Fiddle 中的索引缺失。在生产数据库中,我在开始问题中提到的表上有索引。两列上的单独索引。
【解决方案2】:

尝试以下查询:

select set1.id,set1.bPrice,set2.cPrice from (SELECT a.id,SUM(b.amount * b.price) AS bPrice FROM a JOIN b ON a.id = b.a_id) as set1
JOIN
(SELECT a.id,SUM(c.amount * c.price) AS cPrice FROM a JOIN c ON a.id = c.a_id) as set2 ON set1.id = set2.id

【讨论】:

  • 这个查询也在大约 4 秒内运行,所以不会更快。我还在 JOIN 查询中添加了 GROUP BY a.id
【解决方案3】:

可能值得一试子查询 - 有时它们可​​以更快:

SELECT 
    id, 
    (SELECT SUM(amount * price) AS bPrice FROM b where b.a_id = a.id) AS bPrice, 
    (SELECT SUM(amount * price) AS cPrice FROM c where c.a_id = a.id) AS cPrice
FROM a

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-03-10
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 2014-07-27
    • 1970-01-01
    • 2018-09-06
    • 2018-07-17
    相关资源
    最近更新 更多