2013-06-18 142 views
0

我有1表locations和4個相同的表:countriesregionsprovincescities爲什麼不使用索引鍵?

所有的表的InnoDB

的所有表有一個柱id其是主要,非空,無符號整型,汽車式增量

所有的表列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 countriesINNER 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_length,data_length,auto_increment, create_time),regions表值始終位於其他值之間的某處。

編輯:爲什麼我要問:

查詢與留在區JOIN時間約爲350毫秒(時間:10毫秒,抓取:爲340mS)。

INNER JOIN查詢區域大約需要550ms。 (持續時間:330ms,取指:220ms)。

EDIT2(不完全瞭解,但猜測這與不能夠緩存辦?!):

查詢與地區STRAIGHT_JOIN作爲LEFT JOIN執行好,並提供與INNER JOIN相同的輸出。這很好。但仍然沒有幫助我回答爲什麼regions表的行爲不同。我應該在哪裏看到regions與其他3個看似相同的表格之間的實際差異。

+0

剛剛添加了一個編輯,指出INNER JOIN比LEFT JOIN減少 –

+0

正如@Kickstart指出的那樣,除了INNER JOIN和LEFT JOIN,我還可以做STRAIGHT_JOIN。這似乎與INNER JOIN具有相同的輸出,但性能與LEFT JOIN相同。這很好。但仍然需要弄清楚,爲什麼「地區」表。是什麼讓這張桌子如此不同? –

回答

0

我懷疑這是數據。

locations.id> 1可能根本沒有多大用途來縮小數據範圍,我懷疑位置有很多記錄。

區域可能有較少的記錄,所以使用這個作爲主表來加入其他人可能更有效。也就是說,您的原始查詢會將所有連接限制爲393行,而您的第二個查詢會將區域中只有269行的連接掛起。

如果您希望強制連接的順序,則可以使用STRAIGHT_JOIN。

+0

'locations.id> 1'僅供參數使用;只是爲了讓「位置」表甚至使用一把鑰匙。我不希望「地點」表格是相同的。只有4個「城市」,「地區」,「省份」和「國家」應該相同。 –

+0

您可能可以使用regions.id> 1來產生相同的效果,以強制索引在區域上使用。 MySQL只選擇了記錄數最少的表(以指定的關鍵字段)加入其他INNER JOINed表。 – Kickstart

+0

這是有趣的部分!例如「省份」表格甚至比「地區」表格少**記錄。但對於那張桌子來說並不重要。 「城市」表比**地區表有更多的**記錄。而對於那張桌子也沒關係!所以它似乎與每個「相同」表內的行數沒有關係。 –