LEFT JOIN查询的执行时间太长

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LEFT JOIN查询的执行时间太长相关的知识,希望对你有一定的参考价值。

我有2个表加入:“product”表,这个表包含257613行,这是结构:

id int(11) primary key autoincrement
id_category varchar(100)
name_category varchar(500)
name varchar(1000)
name_translated varchar(1000)
reference varchar(100)
link varchar(1000)
original_price varchar(45)
resell_price varchar(45)
active int(11)
ean varchar(16)
json_detail text
date_add date
date_update date

“stores_product”表,此表包含181142行,这是结构:

id int(11) primary key autoincrement
reference varchar(128)
id_product int(11)
id_image_product int(11)
id_stock_product
id_store int(11)

这是有罪的慢速查询:

SELECT * FROM product AS p 
LEFT JOIN stores_product AS sp ON p.reference = sp.reference 
WHERE sp.id_store = 3

这个查询没有得到我的回复,我在35分钟后阻止了执行而没有结果。要处理的行太多?或者我在查询中出错?

答案

关于这一点有几点需要注意:

  1. 当您在连接字段上有非空条件时(在您的情况下为sp.id_store = 3),进行外连接没有任何好处。由于外连接比内连接更昂贵,因此在这种情况下使用后者:inner join。结果是一样的,但可能更快。
  2. 另一方面,如果您希望通过外部联接列出所有产品,那么您的查询是不正确的。然后,您必须将条件从where子句移到on子句中,如下所示: LEFT JOIN stores_product AS sp ON p.reference = sp.reference AND sp.id_store = 3
  3. 连接条件看起来不像预期的那样。通常情况下,你会期待sp.id_product = p.id。但在评论中你解释这两个领域是无关的。这是一种非常令人困惑的命名方式。您应该考虑在product表中存储引用主键的外键。
  4. 根据数据的分布方式,您将从以下两个索引之一中获益 - 您需要创建它们:stores_product(id_store,reference)或stores_product(reference,id_store)。
  5. 显然,产品(id)应该是主键。

创建缺少的索引,并使用explain select ...查看执行计划,并查看实际使用的是什么。

另一答案

好吧,既然你加入257613行和181142行,那只需要时间。查询很好,我担心除了升级mysql-server之外你无法真正提高性能。尽管数据量很大,35分钟似乎非常长。

您可能还想添加主键,索引和缓存:

另一答案

索引是你的表现救星;使用它们。

SELECT * FROM product AS p 
LEFT JOIN stores_product AS sp
   ON p.reference = sp.reference   -- `p` needs INDEX(reference)
WHERE sp.id_store = 3  -- Needs  INDEX(id_store)

但还有更多......

你对reference的定义是不一致的;修复它。

删除LEFT;你并没有真正做LEFT JOIN,因为你指定sp.id_store。如果它从那里开始,查询将运行得更快。

SELECT *从两个表中获取所有列;这似乎有点矫枉过正。

重新思考你的许多id专栏。似乎比你需要的更多。

如果reference真的是product的唯一标识符,那么使它成为PRIMARY KEY并摆脱id

How to make good indexes

另一答案

知道索引可能导致行更新或插入表中的问题。我建议使用临时表。到目前为止(我知道)它们是在不更改数据库配置中的任何内容的情况下降低计时成本的最佳方法。最后删除临时表总是更好的做法。

所以对于上面的问题。它可以是包含以下内容的存储过程:

select reference, (the columns you need or just *) 
INTO #TempTable
from stores_product sp 
where sp.id_store = 3 

Select * 
from product AS p
left join #TempTable sp ON p.reference = sp.reference 

Drop table #TempTable 

以上是关于LEFT JOIN查询的执行时间太长的主要内容,如果未能解决你的问题,请参考以下文章

sql left join 和 inner join 效率

SQL Server LEFT OUTER JOIN 查询性能

关于Mysql使用left join写查询语句执行很慢的问题解决

何时使用 LEFT JOIN 以及何时使用 INNER JOIN?

sql inner join 与 left join和right join 执行效率上面有多大差别?

MySQL Left join 无法在单个查询中删除重复项