具有多个JOIN varchar条件的表的索引

时间:2017-11-22 06:50:12

标签: mysql innodb

我尝试使用多列匹配查询,以匹配从表A到表B的记录。但由于某种原因,查询运行速度非常慢。我尝试为连接表尝试不同的索引组合,但它们没有被使用,这就是为什么它总是进行全表扫描。

SELECT
    nc.id, nc.firstName, nc.lastName, 
    nc.firmName, nc.location,
    nc.city AS city, nc.state AS state, 
    ac.id, ac.lastName, ac.firstName, ac.middleName, 
    IFNULL(ac.suffixName, '') AS suffixName, ac.firmName, ac.city, ac.state
FROM
    NormalContacts AS nc
JOIN
    AllContacts AS ac ON ((nc.firstName = ac.firstName AND nc.lastName = fa.lastName) OR (nc.firstName = fa.middleName AND nc.lastName = ac.lastName))
        AND (ac.city = nc.city AND ac.state = nc.state)
JOIN
    FirmInputTable AS fit ON (fit.firmName = fa.firmName AND fit.otherFirmName = nc.firmName)       
WHERE
    nc.crdNumber IS NULL AND nc.city IS NOT NULL AND nc.state IS NOT NULL AND nc.firmName IS NOT NULL

NormalContacts是1,000条记录,而AllContacts是337,250条记录。 JOIN条件中的所有字段都是varchar。

以下是EXPLAIN结果:

enter image description here

截图AllContacts中的

* fa,抱歉输入错误。

希望任何人都可以建议一种方法来优化此查询或告诉我我做错了什么。提前谢谢!

1 个答案:

答案 0 :(得分:1)

优化程序将查看索引和统计信息,以确定执行表的顺序。

在下文中,我将假设ON仅说明表格彼此之间的关系,WHERE仅用于过滤。

“第一”表可能(但不一定)是具有最具选择性WHERE条件的表。因此,INDEX需要关注WHERE中的列。 (有时候GROUP BYORDER BY会发挥作用。)

JOIN序列中的其他表将通过“嵌套循环连接”进入。这是“对于前一个表中的每一行,获取当前表中的行”。要执行此操作,它将使用与表相关的任何WHERE子句以及ON中提及此表的任何内容(可能还有以前的表)。因此,请考虑INDEXWHERE条件下此表的ON

由于您无法始终预测优化程序将通过表格的顺序,因此最好添加索引以适应每个可能的顺序。

典型的快捷方式是WHERE只提到一个表。该表几乎肯定会先被选中。

如果特定表格中有WHERE / ON个引导,那么如何为特定表构建一个好的索引?见my cookbook

对于你的情况......

您似乎已正确拆分ONsWHEREs - 好。

nc似乎是WHERE中提到的唯一表格,因此我们可以假设优化工具会从它开始。

IS NULL= constant类似,但IS NOT NULL就像一个范围,并非易于优化。我推荐

nc:  INDEX(crdNumber, state)

(在这里,我猜测哪个nc列最多/最不可能是NULL。)

nc之后,只有ac(又名fa ???)可能会来:

ON    ((...) OR (...))
  AND ac.city = nc...
  AND ac.state = nc...

OR通常无法进行索引或优化,因此我们留下了

ac:  INDEX(city, state)  -- in either order

lastName可能会被OR拉出(在修复ac / fa之后),从而导致

ac:  INDEX(city, state, firstName)  -- in any order

最后,fit

ON    fit.firmName = ...
  AND fit.otherFirmName = ...

导致

fit:  INDEX(firmName, otherFirmName)  -- in either order

修复查询中的fa;如果需要,我会修改我的答案。

注意:在这种情况下,INDEX(a,b)