使用带有OR条件的MySQL JOIN中的索引

时间:2012-06-20 21:17:19

标签: mysql indexing

我正在运行看起来像这样的查询

SELECT parent.field, child.field
FROM parent
JOIN child ON (child.id = parent.id 
    OR child.id = parent.otherid)

然而,这是非常慢的(大约100k记录,并且JOIN到实际版本中的其他表),但尽管尝试了索引

parent.id (PRIMARY),  
parent.otherid,  
child.id (PRIMARY), 
and a composite index of parent.id and parent.otherid

在进行此连接时,我无法让MySQL使用任何这些索引。

我读到MySQL每个连接只能使用一个索引,但是当JOIN包含OR条件时,它是否可以在任何地方找到它是否可以使用复合索引。

有没有人知道是否可以使此查询引用索引? 如果是这样,怎么样?


我的解决方案

(很难让我回答下面的问题)

进行了大量调整,得出了一个相当不错的解决方案,它保留了加入和聚合其他表格的能力。

SELECT parent.field, child.field
FROM parent
JOIN (
    SELECT parent.id as parentid, 
    # Prevents the need to union
    IF(NOT ISNULL(parent.otherid) AND parent.otherid <> parent.id, 
       parent.otherid, 
       parent.id) as getdataforid
    FROM parent
    WHERE (condition)
) as foundrecords
    ON foundrecords.parentid = parent.id
JOIN child ON child.id = parent.getdataforid

对于速度需要子查询中的条件来减少放置在临时表中的记录数,但是我在外部查询上有大量额外的连接,一些连接到子节点,一些连接到父节点(带有一些聚合)所以这个对我来说效果最好。

在很多情况下,联合会更快更有效,但由于我在父级上进行过滤,但是想要从子级(父级自引用)中获取额外的数据,因此联盟会为我创建额外的行,而我无法&# 39;巩固。 可以通过将父对象连接到自身并在外部查询中对where条件进行别名来找到相同的结果,但是这个对我很有效。

感谢Jirka对UNION ALL的建议,这是促使我到达这里的原因:)

2 个答案:

答案 0 :(得分:7)

您的查询在理论上使得单个孩子有两个不同的父母,这将使其成为非常不标准的术语。但是,我们假设您的数据模式使其变得不可能。

然后,下面使用单独的索引给出相同的结果,每列一个索引。

SELECT parent.field, child.field
FROM parent
JOIN child ON child.id = parent.id 

UNION ALL

SELECT parent.field, child.field
FROM parent
JOIN child ON child.id = parent.otherid

答案 1 :(得分:0)

EXPLAIN 
SELECT parent.fld, child.fld 
  FROM parent JOIN child ON child.id = parent.id  
 UNION ALL 
SELECT parent.fld, child.fld
  FROM parent JOIN child ON child.id = parent.otherid
   AND parent.otherid <> parent.id

使用MyISAM引擎的表:

id  select_type   TABLE       TYPE    possible_keys  KEY      key_len  ref                  ROWS  Extra
1   PRIMARY       parent      ALL     PRIMARY                                               9999
1   PRIMARY       child       eq_ref  PRIMARY        PRIMARY  4        test.parent.id       1
2   UNION         parent      ALL     parent_ix1                                            9999  USING WHERE
2   UNION         child       eq_ref  PRIMARY        PRIMARY  4        test.parent.otherid  1
    UNION RESULT  <union1,2>  ALL

使用InnoDB引擎的表:

id  select_type   table       type    possible_keys  key         key_len  ref            rows  Extra
1   PRIMARY       child       ALL     PRIMARY                                            9903
1   PRIMARY       parent      eq_ref  PRIMARY        PRIMARY     4        test.child.id  1
2   UNION         child       ALL     PRIMARY                                            9903
2   UNION         parent      ref     parent_ix1     parent_ix1  5        test.child.id  1     Using where
    UNION RESULT  <union1,2>  ALL