首页 > 解决方案 > MySQL:长时间运行的 LEFT JOIN 查询性能

问题描述

MySQL 数据库包含两个表:customercustmomer_orders

客户表包含 8000 万个条目并包含 80 个字段。其中一些我感兴趣:

  1. 标识 (PK, int(10))
  2. 位置(varchar 255,可为空)。
  3. Registration_Date(日期时间,可为空)。索引。

customer_orders表包含 4000 万个条目,并且仅包含 3 个字段:

  1. 标识 (PK, int(10))
  2. Customer_Id (int(10), FK 到客户表)
  3. Order_Date(日期时间,可为空)

当我运行这样的查询时,执行大约需要 800秒并返回 4000 万个条目:

SELECT o.* 
FROM customer_orders o
LEFT JOIN customer c ON (c.Id = o.Customer_Id) 
WHERE NOT (ISNULL(c.Location)) AND c.Registration_Date < '2018-01-01 00:00:00';

带有 MySQL 服务器的机器有 32GB 的 RAM,28GB 分配给 MySQL。MySQL 版本:5.6.39。

MySQL 在具有这么多记录的表上执行这么长时间的查询是否正常?我怎样才能提高性能?

更新:

customer_orders 表不包含我们想要存储的任何重要数据。这是最近 10 天内下订单的某种复制表。每天我们都会运行一个存储过程,它会删除事务范围内超过 10 天的订单。

有一段时间,这个存储过程由于没有优化查询而超时,订单数量每天都在增长。以前的查询还包含 COUNT 方法,我想它超过了超时。

尽管如此,让我感到惊讶的是,MySQL 最多需要 15 分钟才能在附加条件下获取 40m 条记录。

标签: mysqlsqljoinquery-optimizationquery-performance

解决方案


我认为这很正常。explain如果您分享该查询的返回值,将会很有帮助。

为了优化查询,从 customer_orders 开始可能不是一个好主意,因为无论如何您都没有过滤它(因此它对 40M 记录执行全表扫描)。此外,正如评论中所指出的, LEFT JOIN这里不需要 a 。我会这样写你的查询:

SELECT o.*
FROM customers c, customer_orders o
WHERE c.id = o.Customer_Id
AND   c.Location IS NOT NULL
AND   c.Registration_Date < '2018-01-01'

这将(取决于有多少记录满足子句Registration_Date < '2018-01-01')首先过滤customers表,然后与customer_orders具有索引的表连接customer_id

另外,也许不相关,但是查询返回 40M 记录对您来说是否正常?我的意思是,这就像整张customer_orders桌子。如果我是对的,这意味着所有订单都来自在'2018-01-01'之前注册的客户


推荐阅读