12

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

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

然而,这真的很慢(大约 10 万条记录,并且在真实版本中加入了其他表),但尽管尝试了索引

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

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

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

这里有谁知道是否可以让这个查询引用索引?如果是这样,怎么做?


我的解决方案

(所以不会让我在 atm 下面回答我自己的问题)

一系列调整并提出了一个相当不错的解决方案,它保留了 JOIN 和聚合其他表的能力。

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

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

在许多情况下,联合会更快、更有效,但由于我正在过滤父级,但想要来自子级的额外数据(父级自我引用),联合为我带来了额外的行,我无法合并。只需将 parent 连接到自身并在外部查询中为 where 条件设置别名,就可以找到相同的结果,但这对我来说非常有效。

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

4

2 回答 2

11

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

然后以下使用单独的索引为您提供相同的结果,每列一个索引。

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
于 2012-06-20T21:24:52.867 回答
2
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   
于 2012-06-20T22:04:03.387 回答