0

1 つのテーブルlocationsと 4 つの同一のテーブルがあります: countries、、、regionsprovincescities

すべてのテーブルは InnoDB です

すべてのテーブルには、idPrimary、Non-Null、Unsigned Int、Auto-Increment の列があります

すべてのテーブルには、nameNon-Null、VarChar、デフォルトの列があります ''

locations他の 4 つのテーブルすべてへの外部キーを保持します。すべて非 Null。

テーブルには、他の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 countriesOKです。すべてのテーブルは引き続きキーを使用します。

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 provincesINNER JOIN provincesOKです。すべてのテーブルは引き続きキーを使用します。

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 citiesINNER JOIN citiesOKです。すべてのテーブルは引き続きキーを使用します。

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ですprovincescitiesしかし、この動作は、4 つのテーブルが(テーブルに対して) 同一ではないlocationsことを証明しています。それらをより同一にするために、何を見逃した可能性がありますか?

私はすでに と を見てきましSHOW TABLE STATUS LIKE 'table_name'DESCRIBE table_name。ほとんどすべてが同じです。また、変更がある場合 (例: rowsavg_row_lengthdata_length、)、auto_increment表の値は常に他の値の中間にあります。create_timeregions

編集:私が尋ねている理由:

リージョンで LEFT JOIN を使用したクエリには、約 350 ミリ秒かかります (期間: 10 ミリ秒、フェッチ: 340 ミリ秒)。

リージョンに対する INNER JOIN を使用したクエリには、約 550 ミリ秒かかります。(期間: 330ms、フェッチ: 220ms)。

(正確にはわかりませんが、これはキャッシュできないことに関係していると思いますか?!)

編集2:

領域に対する STRAIGHT_JOIN を使用したクエリは、LEFT JOIN と同じように機能し、INNER JOIN と同じ出力を提供します。これはいい。regionsしかし、それでもテーブルの動作が異なる理由については答えられません。regionsと他の 3 つの一見同一のテーブルの実際の違いを見つけるには、どこを見ればよいでしょうか。

4

1 に答える 1

0

データのせいだと思います。

location.id > 1 はおそらくデータを絞り込むのにあまり役に立たず、場所には多くのレコードがあると思われます。

地域はおそらくレコードが少ないため、これをプライマリ テーブルとして使用して他のテーブルを結合する方がおそらく効率的です。つまり、元のクエリではすべての結合が 393 行に制限されているのに対し、2 番目のクエリでは 269 行のみの領域から結合がハングしています。

結合の順序を強制したい場合は、STRAIGHT_JOIN を使用できます。

于 2013-06-18T13:01:02.137 に答える