2016-11-22 71 views
0

我在加入下面的2个表时遇到问题。我需要的是所有在CLEI或部件号在第二个表中找到的第一个表的零件,与相匹配多少计数有从表1MySQL超级缓慢内部加入组

===================   =================== 
table: svi     table: svp 
===================   =================== 
id       id 
po       price 
customer      clei 
clei       partNumber 
partNumber     description 
====================   =================== 

SVI有大约100万行。 SVP拥有约2000这里是参加我使用...

SELECT svi.clei, 
     svi.partNumber, 
     count(*) 
FROM svp svp 
    INNER JOIN 
     svi svi 
    ON (svp.clei = svi.clei) 
     OR (svp.partNumber = svi.partNumber) 
GROUP BY svi.partNumber 

查询花费有点过了2分钟的运行,这似乎是可笑缓慢。 clei和partNumber在两个表中被索引。我还能做些什么来加速这个连接?

+0

(离题)如果'partNumber'不是表'svi'的'PK',那么你的查询就是无效的SQL。即使MySQL接受它,它也会自由地从SELECT语句中返回表达式svi.clei所需的值。 http://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html – axiac

+0

您的'GROUP BY'也缺少SELECT语句中的非聚合列之一 – Phil

+0

是菲尔那是故意的。每个partNumber只能有1个clei,但每个clei可以有多个partNumber。按partNumber分组只能完成我想要做的事情。 – scott80109

回答

0

这里的索引没有什么帮助,因为对常量没有WHERE条件,并且因为OR运算符。

读取所有2000行的svp表;针对常量的条件减少了从表中读取的行数,但这里没有这样的条件。

然后,对于这2000行中的每一行,在svi表的索引中执行一个或两个查找以标识匹配的行。一个用于clei,如果不成功,另一个用于partNumber。或相反亦然。

svi上的列cleipartNumber上的复合索引对此没有帮助;当条件合并使用OR时,它会有所帮助。

未使用表svp上的索引。如果在svp上包含cleipartNumber列的索引,那么MySQL可以决定在这里读取它,只是因为它包含的数据少于整个表。但它仍然读取整个索引并处理所有行。它不能使用索引来过滤行,因为svp上没有过滤。

它可能更糟糕(阅读整个svi表并使用svp上的索引进行查找),但MySQL足够智能,可以先处理较小的表。

EXPLAIN放在你的查询和MySQL tells you (in less words)之前我试着在上面解释一下。


正如我在评论中所说,查询是无效的SQL。对于svi.partNumber的一个值,您可能有多个值为svi.cleiGROUP BY svi.partNumber子句从表svi中获得的所有行中的单个输出行具有相同的值partNumber

但是,因为存在用于clei两个或更多个不同的值相同partNumber,最终值它图片从SELECT子句表达svi.clei是不确定的。这意味着,如果稍后再运行相同的查询,或者如果在反映数据库的其他服务器上运行它(或者在备份数据库并从备份中恢复之后),它可能会更改。

如果你只是忘记了GROUP BY子句中添加svi.clei那么它是一个容易解决;否则,您必须重新考虑你的查询,因为它是现在,也不会产生预期的结果。

+0

我故意排除了group by子句中的svi.clei,因为单个clei可以有多个partNumber。例如,3层不同的部分看起来是这样的.... CLEI/PARTNUMBER BAC3SY4EAB/11540A-REV-01 BAC3SY4EAB/11540A-REV-02 BAC3SY4EAB/11540A-REV-03 所以我想知道如果我有第一个8个,第二个10个,第四个或第三个。 – scott80109

+0

而且查询似乎是有效的,因为每次运行时我都会得到准确的结果。它只是极其缓慢。 – scott80109

+0

如果单个'clei'有多个'partNumber',它按预期工作(但它仍然是无效的SQL)。您可以在svi.partNumber后面将'svi.clei'放入'GROUP BY'子句中。虽然这可以修复查询,但它并没有提高速度:-(问题出现的时候是另一种方式:一个'partNumber','clei'的多个值。 – axiac