为什么Mysql" where存在"比加入"慢得多?

时间:2017-02-08 15:38:29

标签: mysql sql

我有两个mysql脚本:

select
  p.*
from
    `products` p
    JOIN dispensaries d ON (p.dispensary_id = d.id)
    JOIN dispensary_locations dl ON(dl.dispensary_id = d.id AND dl.is_primary = 1)
    JOIN dispensary_location_zip_codes dlzc ON(dlzc.dispensary_location_id = dl.id AND dlzc.zip_code = '941033')
    and p.`is_hidden` = 0
    and p.`deleted_at` is null
GROUP BY p.id
order by p.`points` desc
limit 12

select
  *
from
  `products`
where
  exists (
    select
      *
    from
      `dispensaries`
    where
      `products`.`dispensary_id` = `dispensaries`.`id`
      and exists (
        select
          *
        from
          `dispensary_locations`
        where
          `dispensary_locations`.`dispensary_id` = `dispensaries`.`id`
          and exists (
            select *
            from
              `dispensary_location_zip_codes`
            where
              `dispensary_location_zip_codes`.`dispensary_location_id` = `dispensary_locations`.`id` and `zip_code` = '941033'
          )
          AND is_primary = 1
      )
  )
order by `points` desc
limit 10;

逻辑它们应该是相同的,但在我的数据库中,当zip_code存在时,第一个需要60毫秒,不存在时需要30毫秒。 当zip_code存在时,第二个需要5毫秒,当zip_code不存在时需要9500毫秒,有没有人知道这里发生了什么?

我在数据库中有大约1万种产品。时代是 第一个脚本为60毫秒和30毫秒,第二个脚本为5毫秒和9500毫秒(9.5秒)...

1 个答案:

答案 0 :(得分:4)

  

为什么Mysql“where where”比“join”慢得多?

在所有情况下都不会慢。它取决于许多因素,如每个表的大小,连接列的索引,值的存在(特别是对于exists语句)等。

例如,让pq为每个表中的条目数。

默认情况下Exists执行嵌套循环,并在找到某个内容后立即停止执行。因此,最坏情况的复杂性(如果值不存在)是O(p*q)

DB Engine如何连接表的粗略草图

嵌套加入

  • 将表格中的每条记录与其他记录进行比较
  • 如果其中一个表非常小
  • ,则此连接效率很高
  • 如果未对连接列编制索引,则为复杂性 - O(p*q)
  • 如果对连接列编制索引的复杂性 - O(p*logq)

哈希加​​入

  • 使用连接属性和行准备较小关系的哈希表。扫描更大的关系。

  • 如果表格足够小以适合内存

  • 复杂性,正如所料 - O(p+q)

合并加入

  • 如果两个表的排序顺序相同。两者都按顺序运行并匹配它们对应的位置。

  • 如果两个表都在连接列上有索引,则索引已按顺序维护它们。因此,复杂性 - O(p+q)

  • 如果一个表在已连接列上具有索引,则在合并步骤发生之前,只需对一个表进行排序。所以,复杂性 - O(p+qlogq)
  • 如果两个表都没有连接列的索引,则必须在合并步骤发生之前对两个表进行排序。所以,复杂性 - O(plogq+qlogq)

在上面的场景中,当zip_codes不存在时,数据库引擎必须对查询2(存在)中的所有条目(O(p*d*dl*dlz))执行嵌套循环,其中在查询1数据库引擎中应用优化连接得到结果。

当zip_codes存在时,在查询2(存在)场景中,它找到匹配的条目而不对所有条目执行嵌套循环。