在具有1对多关系的表上进行1到1左连接的最快方法(MySQL)

时间:2014-10-10 17:47:25

标签: mysql sql

我有两张表有1对多的关系,我正在以1:1的方式进行左连接。查询返回正确的结果,但它显示在我的慢查询日志中(最多需要5秒)。有没有更好的方法来编写此查询?

select * from
tablea a left join tableb b 
  on a.tablea_id = b.tablea_id
  and b.tableb_id = (select max(tableb_id) from tableb b2 where b2.tablea_id = a.tablea_id)

即。我希望TableA加入TableB中最大tableb_id的行。

TableA
tablea_id
1
2

TableB
tableb_id, tablea_id, data
1, 1, x
2, 1, y

Expected Result
tablea_id, tableb_id, data
1, 2, y
2, null, null

TableA的索引为tablea_id,TableB的综合索引为tablea_id,tableb_id

解释输出

+----+--------------------+---------------+--------+-----------------+---------------+---------+----------------------+-------+-------------+
| id | select_type        | table         | type   | possible_keys   | key           | key_len | ref                  | rows  | Extra       |
+----+--------------------+---------------+--------+-----------------+---------------+---------+----------------------+-------+-------------+
|  1 | PRIMARY            | c             | index  | NULL            | department_id | 4       | NULL                 | 18966 | Using index |
|  1 | PRIMARY            | recent_cv_lut | eq_ref | PRIMARY,case_id | PRIMARY       | 4       | func                 |     1 |             |
|  2 | DEPENDENT SUBQUERY | cases_visits  | ref    | case_id         | case_id       | 4       | abcd_records_v2.c.id |     2 | Using index |
+----+--------------------+---------------+--------+-----------------+---------------+---------+----------------------+-------+-------------+

1 个答案:

答案 0 :(得分:3)

可能,相关的子查询正在从tableb执行每一行。

(如果没有EXPLAIN的输出,我们真的只是猜测是否有适当的索引,以及MySQL是否正在使用它们。)

使用内联视图查询可能更有效,一次性获取每个tablea_id的最大tableb_id值,然后使用连接操作。像这样:

SELECT a.*
     , b.*
  FROM tablea a
  LEFT
  JOIN ( SELECT n.tablea_id
              , MAX(n.tableb_id) AS max_tableb_id
           FROM tableb n
          GROUP
             BY n.tablea_id
       ) m
    ON m.tablea_id = a.tablea_id
  LEFT
  JOIN tableb b
    ON b.tablea_id = m.tablea_id
   AND b.tableb_id = m.max_tableb_id

这是另一种选择,但并不能保证会更快。这完全取决于我们没有任何信息的一大堆事情。 (行数,基数,数据类型,可用索引等)


修改

作为替代方案,我们可以在内联视图中进行tablea和tableb之间的连接。这可能会提高性能。 (同样,这实际上取决于很多我们没有任何信息的事情。)

SELECT m.tablea_id
     , m.foo
     , b.*
  FROM ( SELECT a.tablea_id
              , a.foo
              , MAX(n.tableb_id) AS max_tableb_id
           FROM tablea a
           LEFT
           JOIN tableb n ON n.tablea_id = a.tablea_id
          GROUP
             BY a.tablea_id
       ) m
  LEFT
  JOIN tableb b
    ON b.tablea_id = m.tablea_id
   AND b.tableb_id = m.max_tableb_id