【问题标题】:Need a way to optimize the slow SQL Query?需要一种方法来优化慢速 SQL 查询?
【发布时间】:2016-12-15 00:57:55
【问题描述】:

我在 mySQL 服务器上运行更新查询/子查询,需要 12 分钟才能完成,我认为优化不够。

有人可以考虑优化它,让它运行得更快吗?

提前致谢。

UPDATE `TABLE_1` C
INNER JOIN(

    SELECT Cust_No,

    #current year sales

    (SELECT SUM(`Sales`)
    FROM `TABLE_2`
    WHERE Year = 2016
        AND Cust_No = p.Cust_No
    ) as CY_TOTAL_SALES,

    # Get previou year sales

        (SELECT SUM(`Sales`)
    FROM `TABLE_2`
    WHERE Year = 2015
        AND Cust_No = p.Cust_No
    ) as PY_TOTAL_SALES

    FROM `TABLE_2` p
    WHERE Year >= 2015
        AND Year <= 2016

) AS A ON C.`customer_number` = A.Cust_No
    SET C.CY_TOTAL_SALES = A.CY_TOTAL_SALES,
        C.PY_TOTAL_SALES = A.PY_TOTAL_SALES;

TABLE_1 包含 28,000 条记录(customer_number 字段是唯一的并且已建立索引)

TABLE_2 包含 250,000 条记录(Cust_No 不是唯一的,但已建立索引)

它的作用是通过加入 Table_2 来更新 TABLE_1,并使用子查询在 TABLE_2 中总结两年的总销售额,然后将值更新回 TABLE_1,其中 TABLE_1 客户编号与 TABLE_2 Cust_no 匹配。

【问题讨论】:

  • 使用EXPLAIN 运行查询并发布输出。这将显示查询的哪一部分是昂贵的。

标签: mysql sql subquery


【解决方案1】:

我能想到几个可能的解决方案。

方法一

只做一个子查询,不做任何相关的子查询,并根据年份有条件地求和。

UPDATE TABLE_1 C
INNER JOIN (
  SELECT Cust_No, 
    SUM(IF(Year=2015, Sales, 0)) AS PY_TOTAL_SALES,
    SUM(IF(Year=2016, Sales, 0)) AS CY_TOTAL_SALES
  FROM TABLE_2
  WHERE Year IN (2015, 2016)
  GROUP BY Cust_No
) AS S ON C.customer_number = S.Cust_No
SET C.PY_TOTAL_SALES = S.PY_TOTAL_SALES,
    C.CY_TOTAL_SALES = S.CY_TOTAL_SALES;

方法二

根本不做子查询。

首先,将所有客户的总销售额归零:

UPDATE TABLE_1 C
SET C.CY_TOTAL_SALES = 0,
    C.PY_TOTAL_SALES = 0;

然后在不使用任何子查询或SUM() 调用的情况下进行连接,并将每个销售数字一次添加到客户的总销售额中。

UPDATE TABLE_1 AS C
INNER JOIN TABLE_2 AS S ON C.customer_number = S.Cust_No
SET C.CY_TOTAL_SALES = C.CY_TOTAL_SALES + IF(S.Year=2016, S.Sales, 0)
    C.PY_TOTAL_SALES = C.PY_TOTAL_SALES + IF(S.Year=2015, S.Sales, 0)
WHERE S.Year IN (2015, 2016);

对于这两种解决方案,您都需要在 TABLE_2 中的列(Cust_No、Year、Sales)上建立索引。


与此同时,我可以解释一下为什么您的原始查询如此缓慢。您的子查询读取 TABLE_2,您说它有 250,000 行(我假设所有行都在 2015-2016 年),并为每一行计算相应客户的总销售额。这意味着它会为每个客户多次计算相同的总和。

您正在运行 500,000 个相关子查询!只需要12分钟,真的是个奇迹。

在执行此操作时,由于子查询,它会将整个结果保存在一个 250,000 行的临时表中。

然后它将临时表连接到 TABLE_1,并为每个客户设置 CY_TOTAL_SALES 和 PY_TOTAL_SALES。你不知道,但它为每个客户多次设置相同的总数。

【讨论】:

  • 谢谢,我会试试你的解决方案看看。
  • 嗨,比尔,感谢您的详细解释,方法一效果最佳,仅需 1.2 秒。非常感谢您的帮助。
【解决方案2】:

由于新用户声誉,无法添加评论。

如果不查看表结构和当前索引,将很难判断如何优化当前查询。 请编辑您的问题以包含表结构 (show create table)。

【讨论】:

  • 感谢您的回复,为什么表结构有所不同? TABLE_1 有 98 个字段,Customer_Number 设置为 varchar(20) ,TABLE_2 有 25 个字段,字段 cust_no 也设置为 varchar(20) 。两个表在不同字段上都有大约 10 个不同的索引。
  • 我看到你们有一个“更好”的变体——我同意比尔的查询。我想我更像是一个视觉方面的人,想在给出答案之前先玩这个。
  • 该查询的解释也可以告诉您查询中最慢的部分在哪里。这是您在调试查询性能时需要使用的最有用的信息 - 也始终包含这些信息!
猜你喜欢
  • 2021-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多