我有两个表person和city。 person表和city_id表亲自使用city_id连接。 person表包含约million行,而city表包含约10000行。
index person: index1-: id, index2-: city_id
index city: index1-: id
我需要选择所有没有与之相关的人行的城市。城市和人的表如下(演示数据)。
CITY PERSON
id city id name city_id
------------- ------------------
1 city-1 1 name-1 1
2 city-2 2 name-2 2
3 city-3 3 name-3 2
4 city-4 4 name-4 3
5 city-5 5 name-5 1
6 city-6 6 name-6 3
7 city-7 7 name-7 4
8 city-8 8 name-8 8
我写了两个查询来获取结果:
query1:
select c.id, c.city
from city c
left join person p on c.id = p.city_id
where p.id is null
query2:
select *
from city
where id not in ( select distinct city_id from person)
两个查询的执行计划看起来都相似:
然后,我使用性能分析并两次运行了两个查询,以查看它们花费了多少时间:
query1: 0.000729 0.000737 0.000763
query2: 0.000857 0.000840 0.000852
显然,数据查询1优于查询2。
我很困惑,因为我理解query2应该胜过query1。因为query2的嵌套查询使用被索引的city_id,并且mysql可以利用city_id index来获取所有id's,但是query1使用的join将采用两个表的笛卡尔积。是因为我使用了较少的数据f。 人(1000)和城市(200)记录。
由于哪个查询1比查询2表现更好,我缺少什么?
您的效果差异很小。您确实必须多次运行查询,以查看差异是否相关。行数也很小。所有数据很可能仅在一个或两个数据页上。因此,您无法从示例中进行概括(即使结果正确)。
我建议写成:
select c.*
from city c
where not exists (select 1 from person p where p.city_id = c.id);
为了提高性能,您需要在person(city_id)
上建立索引。
这可能与left join
具有相同的执行计划。我只是发现它的意图更清晰-而且它在任何数据库上通常都具有很好的性能。
not in
不完全等效。原因如下:
select distinct
可能会放弃优化器。它不是必需的,但是某些数据库实际上可能运行一个独立的数据库。NULL
s的处理方式不同。如果子查询中的any行返回一个NULL
值,则将从外部查询中返回没有任何行。您可以删除NOT IN中的distinct,因为IN()会自己考虑distinct记录。在上面的查询中,某种程度上的联接得到了更好的优化,因为没有额外的选择来检索联接中的数据。但这仍然取决于。
我通常会说加盟费用很高。