为什么这个JOIN效率低下?

时间:2012-03-17 02:55:50

标签: php mysql optimization join

我试图一次从多个表中获取数据。在我的旧系统中,我会进行查询,获取所需的数据,然后将其用于下一个查询。我想避免进行多次查询,因此我将它们与连接组合在一起:

 SELECT `to`.`id` , `to`.`group`, `to`.`email`, `pTo`.`min_offer`, COUNT(`offerRes`.`id`), `settingsRes`.`email`
                                FROM `members` AS `to`

                                LEFT JOIN (
                                  SELECT `id` , `min_offer`
                                  FROM `profile`
                                ) pTo ON pTo.id = to.id

                                LEFT JOIN (
                                  SELECT `id`, `from`,`to`
                                  FROM `offers`
                                ) offerRes ON offerRes.from = ? && offerRes.to = to.id

                                LEFT JOIN (
                                  SELECT `id`, `email`
                                  FROM `user_settings`
                                )  settingsRes ON settingsRes.id = to.id

                                WHERE to.id = ? LIMIT 1

我使用传入的(to.id)ID来获取配置文件表和商品表以及用户设置表的结果。这些表都具有PRIMARY id,所有内容都映射到该ID。我的PHP用户准备了语句,但是我更换了?在PHPMyAdmin中使用硬值。我的说明如下:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   PRIMARY         to     const    PRIMARY       PRIMARY   4         const     1   
1   PRIMARY     <derived2>  ALL     NULL            NULL    NULL    NULL        45  
1   PRIMARY     <derived3>  ALL     NULL            NULL    NULL    NULL        1   
1   PRIMARY     <derived4>  ALL     NULL            NULL    NULL    NULL        15  
4   DERIVED     user_settingsALL    NULL            NULL    NULL    NULL        15  
3   DERIVED     offers      system  NULL            NULL    NULL    NULL        1   
2   DERIVED     profile     ALL     NULL            NULL    NULL    NULL        45  

为什么MySQL可以在配置文件字段中查看所有45行,因为我的查询基于PRIMARY键id进行简单查找?有什么方法可以让它更有效率?我想要的只是以下表格:

id (from members) - this is optional as this is what is obtained from the user and passed in to SELECT against
group (from members) - corresponding to the id that is passed in
email (from members) - corresponding to the id that is passed in
min_offer (from profile) - also corresponding to the id that is passed in
NUM_ROWS(from offers) - number of rows corresponding to the id taht is passed in and another number that is also passed in.  The offers table has a PRIMARY id but it is a different ID than what is passed in.
email (from user_settings) - corresponding to the id that is passed in

1 个答案:

答案 0 :(得分:3)

  

为什么MySQL在配置文件字段中的所有45行都可以进行简单的查找,因为我的查询基于PRIMARY密钥ID?

因为您正在加入子查询的结果,其中包含表格中的每条记录:

LEFT JOIN (
  SELECT `id` , `min_offer`
  FROM `profile`
) pTo ON pTo.id = to.id

-- etc.

而是直接加入表格:

LEFT JOIN `profile` AS pTo ON pTo.id = to.id

LEFT JOIN `offers` AS offerRes ON offerRes.from = ? && offerRes.to = to.id

LEFT JOIN `user_settings` AS settingsRes ON settingsRes.id = to.id