我有两个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毫秒,是否知道这里发生了什么?
我的数据库中有大约10000种产品。时间是
第一个脚本为60毫秒和30毫秒,第二个脚本为5毫秒和9500毫秒(9.5秒)...
最佳答案
为什么Mysql的“哪里存在”比“加入”要慢得多?
并非在所有情况下都较慢。它取决于许多因素,例如每个表的大小,连接列的索引,值的存在(尤其是存在语句)等。
例如,让p
和q
为每个表中的条目数。
默认情况下,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(存在)场景中,它找到匹配的条目,而没有对所有条目进行嵌套循环。
关于mysql - 为什么Mysql的“哪里存在”比“加入”要慢得多?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42117393/