为什么mysql不使用索引键?

时间:2013-06-18 12:55:37

标签: mysql key describe

我有1个表locations和4个相同的表:countriesregionsprovincescities

所有表格都是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, 

这太奇怪了!因为我可以看到countriesregionsprovincescities完全相同!但是这种行为证明了4个表相同(朝向locations表)。我可以错过什么来使它们更加相同?

我已经查看了SHOW TABLE STATUS LIKE 'table_name'DESCRIBE table_name。几乎一切都是一样的。在有变化的地方(例如rowsavg_row_lengthdata_lengthauto_incrementcreate_time),regions表值始终位于在其他值之间。

编辑:我为什么要问:

在区域上使用LEFT JOIN进行查询大约需要350毫秒(持续时间:10毫秒,获取时间:340毫秒)。

在区域上使用INNER JOIN进行查询大约需要550毫秒。 (持续时间:330毫秒,取:220毫秒)。

(不完全知道,但猜测这与无法缓存有关?!)

EDIT2:

使用区域上的STRAIGHT_JOIN执行与LEFT JOIN一样好,并提供与INNER JOIN相同的输出。这很好。但是,它仍然没有帮助我回答为什么regions表的行为不同。我应该在哪里查看regions与其他3个看似相同的表格之间的实际差异。

1 个答案:

答案 0 :(得分:0)

我怀疑这取决于数据。

locations.id> 1可能没有多大用处来缩小数据范围,我怀疑地点有很多记录。

区域可能记录较少,因此将此作为主表加入其他记录可能更有效。即,原始查询将所有连接挂起,将其限制为393行,而第二个查询挂起仅有269行的连接区域。

如果您想强制加入顺序,可以使用STRAIGHT_JOIN。