【问题标题】:MySQL: query taking more than 30 seconds to executeMySQL:查询执行时间超过 30 秒
【发布时间】:2021-02-18 16:13:55
【问题描述】:

我只是想知道如何在 MySQL 中执行更复杂的查询,而我创建的其中一个查询花费的时间比我预期的要长得多(约 30 秒),我不确定我该怎么做优化查询以更有效地运行。我的查询是为了获取所有之前与我们合作过但在过去 4 个月内未注册为我们目前列出的商店做广告的客户。

我的存档架构如下所示:

|CustomerID | StoreID | DateAdvertised |
|1          | Store1  | 11/01/2020     |
|2          | Store2  | 06/01/2020     |
|1          | Store3  | 08/01/2020     |
.           .         .                .
.           .         .                .

我的客户架构如下所示:

|CustomerID | Name  |  Email       | LastRan    | DNC | IsStore |
|1          | Bob   | bob@email.com| 2020-11-01 | 1   | 0       |
|2          | Joe   | joe@email.com| 2020-06-01 | 0   | 0       |
.           .       .              .
.           .       .              .

我的商店架构如下所示:

|StoreID  | Address      |  Working  |
|Store1   | some address | 1         |
|Store2   | some address | 0         |
|Store3   | some address | 1         |
.         .              .           .
.         .              .           .

在我的查询中,我必须获取客户电子邮件、客户姓名和商店地址以及列出的其他存档数据。我创建了一个查询,其中包括 3 个表上的 3 个连接,以便我可以从每个表中获取我需要的数据,我开始认为这是导致我的查询运行缓慢的原因。

这是我正在使用的查询:

SELECT 
    s.StoreID,
    s.Address,
    c.Name,
    c.CustomerID,
    c.LastRan,
    c.Email
FROM
    Archives a
        JOIN
    Customers c
        JOIN
    Stores s ON (a.CustomerID = c.CustomerID
        AND a.StoreID = s.StoreID
        AND s.Working = '1')
WHERE
    c.DNC = '0' AND c.IsStore = '0'
        AND c.LastRan != ''
        AND c.LastRan != 'N/A'
        AND STR_TO_DATE(c.LastRan, '%m/%d/%Y') < '2020-08-01'
GROUP BY c.CustomerID
HAVING Email != '';

我尝试删除该查询最初必须不包含重复的 CustomerID 值的子查询,但我认为使用 group by 会使其更快一点,但并没有太大的区别。我还尝试删除一些我认为不必要的其他检查,但这些也没有什么不同。如果有人对如何优化查询以提高效率有任何建议,那就太好了。蒂亚!

编辑

解释

编辑 2

仅通过在我的存档和客户架构中向 CustomerID 和 StoreID 添加索引似乎可以更快地运行查询。

【问题讨论】:

  • 您需要添加查询的 EXPLAIN ANALYZE 和所有表的 create table 以查看此类问题的现有索引
  • @nbk 好的,我会看看我能拉出什么
  • 您的 DateAdvertised 列应该是日期类型而不是字符串。不要使用字符串来存储日期
  • @nacho 这会导致性能下降吗?
  • @Luuk 我拥有的档案表是唯一一个在日期格式方面类似的表。不幸的是,我不是那个设置它的人。

标签: mysql


【解决方案1】:
  • 不要将LastRan 存储为字符串;将其存储为DATE 或DATETIME。这消除了不可分割的函数调用,因此将允许以下索引提供帮助:

  • INDEX(DNC, IsStore, LastRan)

  • 如果每个CustomerID 在c 中只有一行,那么将email != '' 放入HAVING 而不是WHERE 没有任何优势。

  • 使用ON 说明表之间的关系;使用WHERE 进行过滤。也就是说,将AND s.Working = '1' 从ON 移动到WHERE。

  • 摆脱对Archives的JOIN;好像没什么用。

  • 如果每个客户只有一行,去掉不必要的GROUP BY。

【讨论】:

    【解决方案2】:

    加入客户表时需要添加“ON”条件

    JOIN Customers c ON c.CustomerID = a.CustomerID
    

    【讨论】:

    • 很好。这可能会迫使它交叉加入
    • 我应该分开做而不是在一个ON 子句中做这两个?
    • 是的,每个 JOIN 都需要一个 ON 子句。 EXPLAIN 将显示它没有使用索引。如果没有 ON 子句,它将 JOIN 表的每一行与当前结果集的每一行匹配。
    【解决方案3】:

    在不改变架构的情况下,唯一可以加快查询速度的方法是将 Email != '' 谓词移动到 'where' 子句中(它本来应该放在的位置)。

    所有非连接谓词都在客户表中 - 建议在这些表上编制索引可能会提高性能 - 但这取决于您的数据分布。此外,仅仅为了解决特定查询的性能而引入索引可能会适得其反。

    【讨论】:

      猜你喜欢
      • 2013-04-01
      • 2019-04-07
      • 2018-08-01
      • 2014-01-20
      • 2011-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多