一个 MySQL 数据库包含两个表:customer 和 custmomer_orders
customer 表包含 8000 万个条目并包含 80 个字段。其中一些我感兴趣:
- Id (PK, int(10))
- 位置(varchar 255,可为空)。
- Registration_Date(日期时间,可为空)。索引。
customer_orders 表包含 4000 万条条目,仅包含 3 个字段:
- Id (PK, int(10))
- Customer_Id(int(10),FK 到客户表)
- 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 内存,其中 28GB 分配给 MySQL。 MySQL版本:5.6.39。
MySQL在记录量这么大的表上执行这么长时间的查询正常吗? 我怎样才能提高性能?
更新:
customer_orders 表不包含我们想要存储的任何重要数据。它是某种复制表,其中包含最近 10 天内的订单。 我们每天都运行一个存储过程,该过程会删除交易范围内超过 10 天的订单。
在某个时刻,这个存储过程由于没有优化查询而超时,订单数量每天都在增长。 先前的查询还包含 COUNT 方法,我想这超过了超时。
然而,令我惊讶的是,MySQL 最多可能需要 15 分钟才能在附加条件下获取 40m 条记录。
最佳答案
我觉得很正常。如果你分享什么会很有帮助 explain
该查询的返回值。
为了优化查询,从 customer_orders 开始可能不是一个好主意,因为您无论如何都不会过滤它(因此它对 40M 记录执行全表扫描)。此外,正如评论中指出的那样,一个 LEFT JOIN
这里不需要。
我会这样写你的查询:
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
table 。如果我是对的,那意味着所有订单都来自于之前“2018-01-01”
关于MySQL:长时间运行的 LEFT JOIN 查询性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54714493/