我在加入下面的2个表时遇到问题。我需要的是第一个表中的所有零件,在第二个表中找到了clei OR零件号,并计算了表1中有多少个匹配项。

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


svi有大约一百万行。 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在两个表中都被索引。我还能做些什么来加快加入速度?

最佳答案

索引在这里没有太大帮助,因为没有针对常量的WHERE条件并且由于OR运算符。

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

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

clei上的列partNumbersvi上的复合索引在这里无济于事;使用OR组合条件时会很有帮助。

不使用表svp上的索引。如果svp上有一个同时包含cleipartNumber列的索引,则MySQL可以决定在此处读取它,因为它包含的数据少于整个表的数据。但是它仍然读取整个索引并处理所有行。它不能使用索引来筛选行,因为svp上没有筛选。

可能会更糟(读取整个svi表并使用svp上的索引进行查找),但是MySQL足够聪明,可以首先处理较小的表。

EXPLAIN放在查询前面,将MySQL tells you (in less words)放在我上面试图解释的地方。



就像我在评论中所说的那样,查询是无效的SQL。对于svi.partNumber的一个值,您可能对svi.clei具有多个值。 GROUP BY svi.partNumber子句从表svi中获得的所有具有相同partNumber值的行中生成一个输出行。

但是,由于同一cleipartNumber有两个或多个不同的值,因此它对于svi.clei子句中的表达式SELECT的最终值是不确定的。这意味着,如果您稍后再次运行同一查询,或者在镜像数据库的其他服务器上运行该查询(或在备份数据库然后从备份还原数据库之后),则可以更改它。

如果您只是忘记在svi.clei子句中添加GROUP BY,那么这是一个简单的解决方法,但是否则您必须重新考虑您的查询,因为到目前为止,它不会产生您期望的结果。

关于mysql - MySQL超慢内部连接与分组依据,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40753431/

10-13 05:59