简体   繁体   中英

Why doesn't mysql use the index key?

I have 1 table locations and 4 identical tables: countries , regions , provinces , cities

All tables are InnoDB

All tables have a column id which is Primary, Non-Null, Unsigned Int, Auto-Increment

All tables have a column name which is Non-Null, VarChar, default ''

locations holds foreign keys to all other 4 tables. All Non-Null.

The locations table also holds some other columns and indexes/keys, but none not related to the other 4 tables

Now I have this query:

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

The result is to my satisfaction: all tables use their key.

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, 

Question :

Changing only LEFT JOIN countries into INNER JOIN countries is ok. All tables still use keys.

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, 

Changing only LEFT JOIN provinces into INNER JOIN provinces is ok. All tables still use keys.

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, 

Changing only LEFT JOIN cities into INNER JOIN cities is ok. All tables still use keys.

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, 

But changing only LEFT JOIN regions into INNER JOIN regions is NOT ok. The regions table doesn't use its key. I get this:

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, 

This is weird! Because countries , regions , provinces , cities are identical as far as I can see! But this behaviour proves the 4 tables are not identical (towards the locations table). What could I have missed looking at to make them more identical?

I have already looked at SHOW TABLE STATUS LIKE 'table_name' and DESCRIBE table_name . Almost everything is identical. And where there are changes (eg rows , avg_row_length , data_length , auto_increment , create_time ), the regions table values are always somewhere in between of the other values.

Edit: Why I'm asking:

Query with LEFT JOIN on regions takes approx 350ms (duration: 10ms, fetch: 340ms).

Query with INNER JOIN on regions takes about 550ms. (duration: 330ms, fetch: 220ms).

(Not exactly knowing, but guessing this has to do with not being able to cache ?!)

Edit2:

Query with STRAIGHT_JOIN on regions performs as good as LEFT JOIN and provides the same output as INNER JOIN. This is good. But still it doesn't help me answer WHY the regions table behaves differently. Where should I look to spot the actual difference between regions and the other 3 seemingly identical tables.

I suspect it is down to the data.

The locations.id > 1 is probably not much use to narrow down the data at all, and I suspect locations has many records.

Regions probably has less records, so using this as the primary table to join others to is probably more efficient. Ie, you original query hangs all the joins off locations which limits it to 393 rows, while your 2nd query hangs the joins off regions which is only 269 rows.

You can use a STRAIGHT_JOIN if you wish to force the order of the joins.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM