比较查询性能:联接与从表中选择不同

问题描述 投票:0回答:2

我有两个表personcityperson表和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)

两个查询的执行计划看起来都相似:

对于查询1:mysq对于查询2:enter image description here

然后,我使用性能分析并两次运行了两个查询,以查看它们花费了多少时间:

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表现更好,我缺少什么?

mysql sql relational-database query-optimization query-performance
2个回答
0
投票

您的效果差异很小。您确实必须多次运行查询,以查看差异是否相关。行数也很小。所有数据很可能仅在一个或两个数据页上。因此,您无法从示例中进行概括(即使结果正确)。

我建议写成:

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不完全等效。原因如下:

  1. select distinct可能会放弃优化器。它不是必需的,但是某些数据库实际上可能运行一个独立的数据库。
  2. NULL s的处理方式不同。如果子查询中的any行返回一个NULL值,则将从外部查询中返回没有任何行

0
投票

您可以删除NOT IN中的distinct,因为IN()会自己考虑distinct记录。在上面的查询中,某种程度上的联接得到了更好的优化,因为没有额外的选择来检索联接中的数据。但这仍然取决于。

我通常会说加盟费用很高。

© www.soinside.com 2019 - 2024. All rights reserved.