我有 1 个表locations
和 4 个相同的表:countries
, regions
, provinces
,cities
所有表都是 InnoDB
所有表都有一个列id
,它是 Primary、Non-Null、Unsigned Int、Auto-Increment
所有表都有一列name
是 Non-Null, VarChar, default ''
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 毫秒)。
(不完全知道,但猜测这与无法缓存有关?!)
编辑2:
在区域上使用 STRAIGHT_JOIN 查询的性能与 LEFT JOIN 一样好,并提供与 INNER JOIN 相同的输出。这很好。但它仍然不能帮助我回答为什么regions
表的行为不同。我应该在哪里发现regions
与其他 3 个看似相同的表之间的实际差异。