Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MySQL:长时间运行的左连接查询性能_Mysql_Sql_Join_Query Optimization_Query Performance - Fatal编程技术网

MySQL:长时间运行的左连接查询性能

MySQL:长时间运行的左连接查询性能,mysql,sql,join,query-optimization,query-performance,Mysql,Sql,Join,Query Optimization,Query Performance,MySQL数据库包含两个表:customer和customer\u orders customer表包含8000万个条目和80个字段。其中一些我感兴趣: Id PK,int10 位置varchar 255,可为空。 注册日期时间,可为空。索引。 customer_orders表包含4000万个条目,仅包含3个字段: Id PK,int10 客户Id int10,FK到客户表 订单日期时间,可为空 当我运行这样的查询时,执行大约需要800秒,并返回4000万个条目: SELECT o.* FRO

MySQL数据库包含两个表:customer和customer\u orders

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

Id PK,int10 位置varchar 255,可为空。 注册日期时间,可为空。索引。 customer_orders表包含4000万个条目,仅包含3个字段:

Id PK,int10 客户Id int10,FK到客户表 订单日期时间,可为空 当我运行这样的查询时,执行大约需要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分钟才能获取4000万条记录。

这是一个很长的评论

关于查询,首先要注意的是,它实际上并没有执行左联接,因为它在WHERE子句中具有引用左联接表的条件

它可以改写为:

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';

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

这是一个注释

关于查询,首先要注意的是,它实际上并没有执行左联接,因为它在WHERE子句中具有引用左联接表的条件

它可以改写为:

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';

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

如果我的评论和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'
);

如果我的评论和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'
);

我觉得这很正常。如果您共享该查询的解释返回内容,这将非常有用

为了优化查询,从customer_订单开始可能不是一个好主意,因为您无论如何都不会对其进行筛选,因此它会对4000万条记录执行全表扫描。此外,正如注释中所指出的,这里不需要左连接。 我会这样写您的查询:

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'
这将取决于满足条款注册日期<'2018-01-01'的记录数量,首先过滤customers表,然后与customer orders表合并,customer orders表具有客户id并按客户id索引


另外,可能不相关,但查询返回4000万条记录对您来说是否正常?我的意思是,这就像整个客户订单表。如果我是对的,这意味着所有订单都来自于“2018-01-01”之前注册的客户。

我认为这是正常的。如果您共享该查询的解释返回内容,这将非常有用

为了优化查询,从customer_订单开始可能不是一个好主意,因为您无论如何都不会对其进行筛选,因此它会对4000万条记录执行全表扫描。此外,正如注释中所指出的,这里不需要左连接。 我会这样写您的查询:

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'
这将取决于满足条款注册日期<'2018-01-01'的记录数量,首先过滤customers表,然后与customer orders表合并,customer orders表具有客户id并按客户id索引


另外,可能不相关,但查询返回4000万条记录对您来说是否正常?我的意思是,这就像整个客户订单表。如果我是对的,这意味着所有订单都来自“2018-01-01”之前注册的客户。

我想发表评论,但改变了主意,同意回答

因为主要问题是你的问题本身

我不知道你的客户订单有多少栏,但是如果你< /p> 4000万份参赛作品

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

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

EXPLAIN SELECT ...your query here... ;
然后执行

EXPLAIN SELECT ...your query here... LIMIT 1;
尝试将结果限制为1000,例如:

SELECT ...your query here... LIMIT 1000;

当您对这些查询有了答案、输出和统计数据后,我们可以讨论您的以下步骤。

我想发表评论,但改变了主意,同意回答

因为主要问题是你的问题本身

我不知道你的客户订单有多少栏,但是如果你

4000万份参赛作品

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

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

EXPLAIN SELECT ...your query here... ;
然后执行

EXPLAIN SELECT ...your query here... LIMIT 1;
尝试将结果限制为1000,例如:

SELECT ...your query here... LIMIT 1000;

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

1仅选择您实际需要的字段;2该查询似乎没有理由使用左连接而不是内部连接,因为您的WHERE条件实际上使其成为内部连接;连接中使用的3个字段和条件应编入索引的位置。令人印象深刻的是,订单数量比客户数量少。连接一个没有选择列的表没有任何意义。但是,WHERE子句将左连接呈现为内部连接,因此您也可以这样开始编写。1只选择实际需要的字段;2该查询似乎没有理由使用左连接而不是内部连接,因为您的WHERE条件实际上使其成为内部连接;连接中使用的3个字段和条件应编入索引的位置。令人印象深刻的是,订单数量比客户数量少。连接一个没有选择列的表没有任何意义。然而,WHERE子句将左连接呈现为内部连接,因此您可以这样开始编写。很好,谢谢。但不幸的是,这也花了约550秒。在选择。。。是的,这很少是我的第一选择;但在某些情况下,它可能是最好的。很好,谢谢。但不幸的是,这也花了约550秒。在选择。。。是的,这很少是我的第一选择;但在某些情况下,它可能是最好的;索引中的顺序不正确。一旦找到range子句,索引的其余部分就没用了。位置不为空且日期<。。。都是射程。例外情况是当索引覆盖时,在本例中就是这样。在这种情况下,我会将位置或注册日期放在第一位,因为它在WHERE中,与常量相比;索引中的顺序不正确。一旦找到range子句,索引的其余部分就没用了。位置不为空且日期<。。。都是射程。例外情况是当索引覆盖时,在本例中就是这样。在这种情况下,我会先输入Location或Registration_Date,因为它位于WHERE中,并与常量进行比较。EXPLAIN通常忽略限制。所以我在第二个解释中没有预测任何有用的信息。解释通常忽略了极限。所以我在第二个解释中没有预测任何有用的信息。