MySQL数据库包含两个表: customer 和 custmomer_orders
客户表包含8000万个条目,并包含80个字段。我对其中一些感兴趣:
customer_orders 表包含4000万个条目,并且仅包含3个字段:
当我运行这样的查询时,它需要〜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条带有附加条件的记录。
答案 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
当您对这些查询有答案,输出和统计信息时,我们可以讨论您的以下步骤。