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.