MySQL:长期运行的LEFT JOIN查询性能

时间:2019-02-15 17:42:26

标签: mysql sql performance left-join query-performance

MySQL数据库包含两个表: customer custmomer_orders

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

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

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

  1. Id(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条带有附加条件的记录。

4 个答案:

答案 0 :(得分:2)

我认为这很正常。如果您共享lst = list() while 1: numbers = input("Enter the number::") if numbers == "done" : break else : acceptable_numbers = int(numbers) lst.append(acceptable_numbers) print("List before sorting :: ", lst) sortedList = lst.sort() print("List after sorting:: ", sortedList) 对于该查询返回的内容,将会很有帮助。

为了优化查询,从customer_orders开始可能不是一个好主意,因为无论如何您都不会对其进行过滤(因此它正在对4000万条记录执行全表扫描)。另外,如注释中所指出的,此处不需要explain。 我会这样写你的查询:

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表联接

此外,也许不相关,但是查询返回40M记录对您来说是否正常?我的意思是,这就像整个customer_id表一样。如果我是对的,则意味着所有订单均来自客户在之前'2018-01-01'

注册的订单

答案 1 :(得分:1)

这很想发表评论...

关于查询的第一件事要注意的是,它实际上并没有执行LEFT JOIN,因为它在WHERE子句中有引用LEFT JOIN ed表的条件。 / p>

它可以改写为:

SELECT o.* 
FROM customer_orders o
INNER JOIN customer c 
    ON c.Id = o.Customer_Id
    AND c.Location is NOT NULL
    AND c.Registration_Date < '2018-01-01 00:00:00';

明确说明联接类型有利于提高可读性,并且可以帮助MySQL为查询找到更好的执行路径。

关于性能,基本建议是,对于此查询,您需要在所有要搜索的三列上使用复合索引,其顺序与查询中使用的顺序相同(通常,您希望将限制性更强的条件放在开头,所以您可能需要对此进行调整:

ALTER TABLE mytable ADD INDEX (Id, Location, Registration_Date );

有关性能的更多建议,您可能希望使用表的CREATE TABLE语句和查询的执行计划来更新问题。

答案 2 :(得分:1)

如果我的评论和GMB的回答最终并没有帮助改善性能;您可以随时尝试使用其他方法编写查询。我通常更喜欢联接而不是子查询,但是有时候它们成为处理数据的最佳选择。

由于您已经说过,customers表与orders表相比相对较大,所以这可能是其中一种情况。

SELECT o.* 
FROM customer_orders AS o
WHERE o.Customer_Id IN (
     SELECT Id 
     FROM customer 
     WHERE Location IS NOT NULL 
        AND Registration_Date < '2018-01-01 00:00:00'
);

答案 3 :(得分:1)

我想发表评论,但改变主意去回答。

因为主要问题是您自己的问题。

我不知道您的customer_orders有多少列,但是如果您得到

  

4000万条目

回来。我会说你做错了。 可能不是查询本身很慢,而是数据获取。

要证明尝试对您的查询执行EXPLAIN

EXPLAIN SELECT ...your query here... ;

然后执行

EXPLAIN SELECT ...your query here... LIMIT 1;

例如,尝试将结果LIMIT SELECT ...your query here... LIMIT 1000;

:hover

当您对这些查询有答案,输出和统计信息时,我们可以讨论您的以下步骤。