最有效的方式加入"最近的行"

时间:2017-05-08 16:02:10

标签: mysql sql join query-optimization

我知道这个问题已被问过100次了,这不是"我该怎么做",而是一个效率问题 - 一个我不太了解的话题。

从我的网络阅读中我已经找到了解决最近问题的一种方法,这种方法听起来非常有效 - LEFT JOIN a" max" table(按匹配条件分组)然后LEFT JOIN匹配分组条件的行。像这样:

 Select employee.*, evaluation.* form employee 
 LEFT JOIN (select max(report_date) report_date, employee_id 
      from evaluation group by employee_id) most_recent_eval 
    on most_recent_eval.employee_id = employee.id
 LEFT JOIN evaluation 
    on evaluation.employee_id = employee.id and evaluation.report_date = most_recent_eval.report_date

我不知道这有什么问题吗?这是2次表扫描(一次是查找最大值,一次是查找行)?是否必须为每位员工进行2次完整扫描?

我问的原因是我现在正在考虑加入3个表格,我需要最新的行(评估,安全许可和项目),似乎任何低效率都将大量增加。

有人可以给我一些建议吗?

1 个答案:

答案 0 :(得分:0)

您建议的查询模式应该处于良好的状态。

一个可能的建议,如果您的evaluation表格有自己的自动增量id列,这将有所帮助。您可能能够使用此子查询找到每个员工的最新评估:

            SELECT MAX(id) id
              FROM evaluation
             GROUP BY employee_id

然后您的加入可能如下所示:

        FROM employee
   LEFT JOIN (
               SELECT MAX(id) id
                 FROM evaluation
                GROUP BY employee_id
             ) most_recent_eval ON most_recent_eval.employee_id=employee.id
   LEFT JOIN evaluation ON most_recent_eval.id = evaluation.id

如果id表中的report_date值和evaluation值的顺序相同,则此方法有效。只有你知道你的申请中是否属于这种情况。但如果是,这是一个非常有用的优化。

除此之外,您可能需要向某些表添加一些复合索引以加快查询速度。首先让他们正常工作。阅读http://use-the-index-luke.com/。请记住,许多单列索引通常对MySQL查询性能有害,除非他们选择加速特定查询。

如果在(employee_id, report_date)上创建复合索引,则此子查询

 select max(report_date) report_date, employee_id 
   from evaluation
  group by employee_id

可以满足于令人惊讶的效率loose index scan。同样,如果您使用InnoDB,则查询

            SELECT MAX(id) id
              FROM evaluation
             GROUP BY employee_id

可以通过employee_id上的单列索引上的松散索引扫描来满足。 (如果您正在使用MyISAM,则需要(employee_id, id)上的复合索引,因为InnoDB将主键列隐式放入每个索引中。)