我有1个表locations
和4个相同的表:countries
,regions
,provinces
,cities
所有表格都是InnoDB
所有表都有一列id
,它是主要的,非空的,无符号的Int,自动增量
所有表都有一列name
,它是非空的,VarChar,默认为''
locations
持有所有其他4个表的外键。全部非空。
locations
表还包含一些其他列和索引/键,但没有一个与其他4个表无关
现在我有了这个问题:
DESCRIBE SELECT * FROM locations
LEFT JOIN cities ON locations.city_id = cities.id
LEFT JOIN provinces ON locations.province_id = provinces.id
LEFT JOIN regions ON locations.region_id = regions.id
LEFT JOIN countries ON locations.country_id = countries.id
WHERE locations.id > 1
结果令我满意:所有桌子都使用他们的钥匙。
1, SIMPLE, locations, range , PRIMARY, PRIMARY, 4, , 393, Using where
1, SIMPLE, cities , eq_ref, PRIMARY, PRIMARY, 4, mydb.locations.city_id , 1,
1, SIMPLE, provinces, eq_ref, PRIMARY, PRIMARY, 4, mydb.locations.province_id, 1,
1, SIMPLE, regions , eq_ref, PRIMARY, PRIMARY, 4, mydb.locations.region_id , 1,
1, SIMPLE, countries, eq_ref, PRIMARY, PRIMARY, 4, mydb.locations.country_id , 1,
问题:
仅将LEFT JOIN countries
更改为INNER JOIN countries
即可。所有表格仍然使用密钥。
1, SIMPLE, locations, range , PRIMARY,locations_country_id_fk, PRIMARY, 4, , 341, Using where
1, SIMPLE, cities , eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.city_id , 1,
1, SIMPLE, provinces, eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.province_id, 1,
1, SIMPLE, regions , eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.region_id , 1,
1, SIMPLE, countries, eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.country_id , 1,
仅将LEFT JOIN provinces
更改为INNER JOIN provinces
即可。所有表格仍然使用密钥。
1, SIMPLE, locations, range , PRIMARY,locations_province_id_fk, PRIMARY, 4, , 341, Using where
1, SIMPLE, provinces, eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.province_id, 1,
1, SIMPLE, regions , eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.region_id , 1,
1, SIMPLE, countries, eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.country_id , 1,
1, SIMPLE, cities , eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.city_id , 1,
仅将LEFT JOIN cities
更改为INNER JOIN cities
即可。所有表格仍然使用密钥。
1, SIMPLE, locations, range , PRIMARY,locations_city_id_fk, PRIMARY, 4, , 341, Using where
1, SIMPLE, provinces, eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.province_id, 1,
1, SIMPLE, regions , eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.region_id , 1,
1, SIMPLE, countries, eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.country_id , 1,
1, SIMPLE, cities , eq_ref, PRIMARY , PRIMARY, 4, ftc_dev.locations.city_id , 1,
但仅将LEFT JOIN regions
更改为INNER JOIN regions
不确定。 regions
表不使用其密钥。我明白了:
1, SIMPLE, regions , ALL , PRIMARY , null , null, null , 269,
1, SIMPLE, locations, ref , PRIMARY,locations_region_id_fk, locations_region_id_fk, 5, mydb.regions.id , 1, Using where
1, SIMPLE, cities , eq_ref, PRIMARY , PRIMARY , 4, mydb.locations.city_id , 1,
1, SIMPLE, provinces, eq_ref, PRIMARY , PRIMARY , 4, mydb.locations.province_id, 1,
1, SIMPLE, countries, eq_ref, PRIMARY , PRIMARY , 4, mydb.locations.country_id , 1,
这太奇怪了!因为我可以看到countries
,regions
,provinces
,cities
完全相同!但是这种行为证明了4个表不相同(朝向locations
表)。我可以错过什么来使它们更加相同?
我已经查看了SHOW TABLE STATUS LIKE 'table_name'
和DESCRIBE table_name
。几乎一切都是一样的。在有变化的地方(例如rows
,avg_row_length
,data_length
,auto_increment
,create_time
),regions
表值始终位于在其他值之间。
编辑:我为什么要问:
在区域上使用LEFT JOIN进行查询大约需要350毫秒(持续时间:10毫秒,获取时间:340毫秒)。
在区域上使用INNER JOIN进行查询大约需要550毫秒。 (持续时间:330毫秒,取:220毫秒)。
(不完全知道,但猜测这与无法缓存有关?!)
EDIT2:
使用区域上的STRAIGHT_JOIN执行与LEFT JOIN一样好,并提供与INNER JOIN相同的输出。这很好。但是,它仍然没有帮助我回答为什么regions
表的行为不同。我应该在哪里查看regions
与其他3个看似相同的表格之间的实际差异。
答案 0 :(得分:0)
我怀疑这取决于数据。
locations.id> 1可能没有多大用处来缩小数据范围,我怀疑地点有很多记录。
区域可能记录较少,因此将此作为主表加入其他记录可能更有效。即,原始查询将所有连接挂起,将其限制为393行,而第二个查询挂起仅有269行的连接区域。
如果您想强制加入顺序,可以使用STRAIGHT_JOIN。