mysql加入效率 - 加入哪里然后加入其他东西

时间:2017-07-16 14:44:35

标签: mysql sql join

我有一个如下所示的查询:

select `adverts`.*
 from `adverts` 
    inner join `advert_category` on `advert_category`.`advert_id` = `adverts`.`id`
    inner join `advert_location` on `adverts`.`id` = `advert_location`.`advert_id`
    where `advert_location`.`location_id` = ? 
    and `advert_category`.`category_id` = ?
    order by `updated_at` desc

这里的问题是我有一个庞大的数据库,这个响应绝对会破坏我的数据库。

我真正需要的是做第一次连接,然后在那里做where子句。这会将我的响应从100k查询减少到不到10k,然后我想进行其他加入,以便再次减少响应,这样我就可以在类别项上获得advert_location。

这样做是不可行的。

那么,我如何使用join和where条件,然后在获得响应后再使用where条件进行连接?

由于

3 个答案:

答案 0 :(得分:1)

这是你的查询,写得有点简单,所以我可以阅读它:

select a.*
from adverts a inner join 
     advert_category ac
     on ac.advert_id = a.id inner join
     advert_location al
     on al.advert_id = a.id
where al.location_id = ? and
      ac.category_id = ?
order by a.updated_at desc;

我推测advert_categoryadvert_locations每个广告有多行。在这种情况下,您将获得每个广告的笛卡尔积。

编写查询的更好方法是使用exists

select a.*
from adverts a
where exists (select 1
              from advert_location al
              where al.advert_id = a.id and al.location_id = ?
             ) and
      exists (select 1
              from advert_category ac
              where ac.advert_id = a.id and ac.category_id = ?
             )
order by a.updated_at desc;

对于此版本,您需要advert_location(advert_id, location_id)advert_category(advert_id, category_id)advert(updated_at, id)上的索引。

答案 1 :(得分:0)

您可以在包含WHERE条件的派生表中编写第一个连接,然后执行第二个连接(但是一个不错的优化器可能会再次解析派生表并根据统计信息执行他认为最好的):

select adverts.*
from
  (
   select `adverts`.*
   from `adverts` 
   inner join `advert_category`
     on `advert_category`.`advert_id` =`adverts`.`id`
   where `advert_category`.`category_id` = ?
 ) as adverts
inner join `advert_location`
  on `adverts`.`id` = `advert_location`.`advert_id`
where `advert_location`.`location_id` = ? 
order by `updated_at` desc

答案 2 :(得分:0)

MySQL将在优化期间为您重新排序内部联接,无论您在查询中如何编写它们。内部连接在任一方向都是相同的(在代数中称为可交换),因此这是安全的。

如果在查询中使用EXPLAIN,则可以看到联接重新排序的结果。

如果您不喜欢MySQL为您的联接选择的顺序,您可以使用以下语法覆盖它:

from `adverts` 
straight_join `advert_category` ...

https://dev.mysql.com/doc/refman/5.7/en/join.html说:

  

STRAIGHT_JOIN类似于JOIN,只是左表始终在右表之前读取。这可以用于连接优化器以次优顺序处理表的那些(少数)情况。

一旦优化器决定了连接顺序,它总是按顺序一次连接一个。这称为嵌套连接方法。

实际上没有任何方法可以进行连接然后执行where子句"。查找连接表的行时,条件组合在一起。但这是一件好事,因为您可以创建一个复合索引,以帮助根据连接条件和条件匹配行。

PS:在询问查询优化问题时,您应该包含EXPLAIN输出,并为每个表运行SHOW CREATE TABLE <tablename>,并包含结果。然后我们不必猜测表格中的列和索引。