【explain】MySQL連結テーブルクエリのドライバテーブル
前に書く
1、連結テーブルクエリー(join/left join/inner joinなど)のmysql演算プロセスを必ず理解する必要はありません.
2、オンライン(現在または未来)のどのテーブルのデータ量が大きいか、どのテーブルのデータ量が小さいか、誰もが必ず知っていることを要求しない
3、しかしmysqlクライアント(例えばSQLyog、例えばHeidiSQL)をデスクトップの上に置いて、時々explainを出して、これは1種の美徳です!
インスタンスの説明に先立ち、次の連結テーブル・クエリーの基礎知識をレビューします.
結合テーブルクエリの基礎知識
引用子:なぜ最初のクエリーはusing temporaryで、2番目のクエリーはテンポラリ・テーブルを使用しないのですか.
次の2つのクエリは、order byが1つしか残っていませんが、効果は大きく異なります.
最初のクエリ:
実行計画は次のとおりです.
2番目のクエリ:
実行計画にはusing temporaryがありません.
どうして?DBAは次のように教えてくれます.
EXPLAINの結果、1行目に出てくるテーブルが駆動テーブル(Important!)
以上の2つのクエリー文は、上記の実行計画に示すように、ドライバテーブルがcityです.
ドライバテーブルは直接ソートできます.非ドライバテーブル(のフィールドソート)は、循環クエリーの集計結果(テンポラリテーブル)をソートする必要があります(Important!)
だからorder by ads.id descの場合、まずusing temporary!
ドライバテーブルの定義
wwh 999は2006年に、マルチテーブル接続クエリーを行う場合、[ドライバテーブル]の定義は以下の通りであるとまとめた.
1)結合条件が指定されている場合、クエリ条件を満たすレコード行数が少ないテーブルは[ドライバテーブル]
2)結合条件が指定されていない場合、行数の少ないテーブルは[ドライバテーブル](Important!)
アドバイス:誰にドライバテーブルをやらせるべきか、誰がjoinをやらせるべきか分からない場合は、MySQLの実行時に自分で判断させてください.
「接続条件が指定されていない場合、行数の少ないテーブルは[ドライバテーブル]です.また、自分が書いた複雑なNested Loop Joinについてもあまり自信がないので(以下の例に示すように)、誰のleft/right joinを指定するのではなく、MySQLオプティマイザの実行時にお任せください.
自分に特に自信があれば、火丁のように最適化することができます.
小結果セット駆動大結果セット
de.celは2012年に、あなたもMySQLも、JOINのNested Loopのサイクル数をできるだけ減らすことを最適化したとまとめた.
これにより、大きな結果セット(Important!)を常に小さな結果セットで駆動することが保証されます.
実例説明
Nested Loop Join SQL文をゆっくり調べる
まずmbテーブルに千万級の記録があることを理解して、mbeiテーブルはずっと少ないです.スローチェックの例は次のとおりです.
複雑でしょう.Nested Loop Joinは、テーブルの結果セットをループの基礎データとして駆動し、結果セットのデータをフィルタ条件として次のテーブルに1つずつクエリーし、結果をマージします.
このとき3番目のテーブルがある場合は、前の2つのテーブルのJoin結果セットをループベースデータとし、3番目のテーブルにもう一度ループクエリー条件を介してデータをクエリーすることを繰り返す.
この文の実行計画は次のとおりです.
「LEFT JOIN」が動員されたため、攻城ライオンはすでに駆動表を指定したが、この駆動表の結果セット記録数は百万級に達した!
最適化方法
最適化の第一歩:LEFT JOINをJOINに変更して、どうしてleft joinを要しますか?直接join!
すぐに現れて、駆動表はすぐに小表mbeiになって、Using temporaryは消えて、影響行数は少なくなりました:
最適化の最初のステップのブランチ1:ドライバテーブルのフィールドに基づいてソートしてもいいですか?
left joinは変わらない.なぜ非駆動テーブルのフィールドに基づいてソートするのですか?前述したように、「ドライバ・テーブルを直接ソートできます.非ドライバ・テーブル(のフィールド・ソート)をソートするには、循環クエリーの集計結果(テンポラリ・テーブル)をソートする必要があります.」のです.
ビジネスシーンも満たし、rowsを最小限に抑えることができます.
最適化の第2歩:すべてのJOINを除去して、MySQLに自分で決定させます!こんなにびっしり書かれたleft join/inner joinは楽しかったですか?
すぐに現れ、駆動表は同じ小表mbeiです.
最後のまとめ:
強調して強調する.
1、運を信じすぎないように!
2、あなたの開発環境のSQLの実行速度を信じないでください!
3、explain武器を取ってください.以下の現象を見たら、最適化してください.
1)Using temporaryが出現
2)rowsが多すぎたり、ほぼ全テーブルのレコード数
3)key Yes(NULL)
4)possible_keysインデックスが多すぎる(選択される)
覚えておいて、explainは美徳です!
1、連結テーブルクエリー(join/left join/inner joinなど)のmysql演算プロセスを必ず理解する必要はありません.
2、オンライン(現在または未来)のどのテーブルのデータ量が大きいか、どのテーブルのデータ量が小さいか、誰もが必ず知っていることを要求しない
3、しかしmysqlクライアント(例えばSQLyog、例えばHeidiSQL)をデスクトップの上に置いて、時々explainを出して、これは1種の美徳です!
インスタンスの説明に先立ち、次の連結テーブル・クエリーの基礎知識をレビューします.
結合テーブルクエリの基礎知識
引用子:なぜ最初のクエリーはusing temporaryで、2番目のクエリーはテンポラリ・テーブルを使用しないのですか.
次の2つのクエリは、order byが1つしか残っていませんが、効果は大きく異なります.
最初のクエリ:
EXPLAIN extended
SELECT ads.id FROM ads, city
WHERE
city.city_id = 8005
AND ads.status = 'online'
AND city.ads_id=ads.id
ORDER BY ads.id desc
実行計画は次のとおりです.
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using temporary; Using filesort
1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
2番目のクエリ:
EXPLAIN extended
SELECT ads.id FROM ads,city
WHERE
city.city_id =8005
AND ads.status = 'online'
AND city.ads_id=ads.id
ORDER BY city.ads_id desc
実行計画にはusing temporaryがありません.
id select_type table type possible_keys key key_len ref rows filtered Extra
1 SIMPLE city ref ads_id,city_id city_id 4 const 2838 100.00 Using where; Using filesort
1 SIMPLE ads eq_ref PRIMARY PRIMARY 4 city.ads_id 1 100.00 Using where
どうして?DBAは次のように教えてくれます.
MySQL Nest Loop Join, , , 。
EXPLAINの結果、1行目に出てくるテーブルが駆動テーブル(Important!)
以上の2つのクエリー文は、上記の実行計画に示すように、ドライバテーブルがcityです.
ドライバテーブルは直接ソートできます.非ドライバテーブル(のフィールドソート)は、循環クエリーの集計結果(テンポラリテーブル)をソートする必要があります(Important!)
だからorder by ads.id descの場合、まずusing temporary!
ドライバテーブルの定義
wwh 999は2006年に、マルチテーブル接続クエリーを行う場合、[ドライバテーブル]の定義は以下の通りであるとまとめた.
1)結合条件が指定されている場合、クエリ条件を満たすレコード行数が少ないテーブルは[ドライバテーブル]
2)結合条件が指定されていない場合、行数の少ないテーブルは[ドライバテーブル](Important!)
アドバイス:誰にドライバテーブルをやらせるべきか、誰がjoinをやらせるべきか分からない場合は、MySQLの実行時に自分で判断させてください.
「接続条件が指定されていない場合、行数の少ないテーブルは[ドライバテーブル]です.また、自分が書いた複雑なNested Loop Joinについてもあまり自信がないので(以下の例に示すように)、誰のleft/right joinを指定するのではなく、MySQLオプティマイザの実行時にお任せください.
自分に特に自信があれば、火丁のように最適化することができます.
小結果セット駆動大結果セット
de.celは2012年に、あなたもMySQLも、JOINのNested Loopのサイクル数をできるだけ減らすことを最適化したとまとめた.
これにより、大きな結果セット(Important!)を常に小さな結果セットで駆動することが保証されます.
実例説明
Nested Loop Join SQL文をゆっくり調べる
まずmbテーブルに千万級の記録があることを理解して、mbeiテーブルはずっと少ないです.スローチェックの例は次のとおりです.
explain
SELECT mb.id, ……
FROMmb LEFT JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid
WHERE 1=1
ORDER BY mbei.apply_time DESC
limit 0,10
複雑でしょう.Nested Loop Joinは、テーブルの結果セットをループの基礎データとして駆動し、結果セットのデータをフィルタ条件として次のテーブルに1つずつクエリーし、結果をマージします.
このとき3番目のテーブルがある場合は、前の2つのテーブルのJoin結果セットをループベースデータとし、3番目のテーブルにもう一度ループクエリー条件を介してデータをクエリーすることを繰り返す.
この文の実行計画は次のとおりです.
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE mb index userid userid 4 (NULL) 6060455 Using index; Using temporary; Using filesort
1 SIMPLE mbei eq_ref mb_id mb_id 4 mb.id 1
1 SIMPLE u eq_ref PRIMARY PRIMARY 4 mb.uid 1 Using index
「LEFT JOIN」が動員されたため、攻城ライオンはすでに駆動表を指定したが、この駆動表の結果セット記録数は百万級に達した!
最適化方法
最適化の第一歩:LEFT JOINをJOINに変更して、どうしてleft joinを要しますか?直接join!
explain
SELECT mb.id……
FROM mb JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid
WHERE 1=1
ORDER BY mbei.apply_time DESC
limit 0,10
すぐに現れて、駆動表はすぐに小表mbeiになって、Using temporaryは消えて、影響行数は少なくなりました:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE mbei ALL mb_id (NULL) (NULL) (NULL) 13383 Using filesort
1 SIMPLE mb eq_ref PRIMARY,userid PRIMARY 4 mbei.mb_id 1
1 SIMPLE u eq_ref PRIMARY PRIMARY 4 mb.uid 1 Using index
最適化の最初のステップのブランチ1:ドライバテーブルのフィールドに基づいてソートしてもいいですか?
left joinは変わらない.なぜ非駆動テーブルのフィールドに基づいてソートするのですか?前述したように、「ドライバ・テーブルを直接ソートできます.非ドライバ・テーブル(のフィールド・ソート)をソートするには、循環クエリーの集計結果(テンポラリ・テーブル)をソートする必要があります.」のです.
explain
SELECT mb.id……
FROM mb LEFT JOIN mbei ON mb.id=mbei.mb_id INNER JOINu ON mb.uid=u.uid
WHERE 1=1
ORDER BY mb.id DESC
limit 0,10
ビジネスシーンも満たし、rowsを最小限に抑えることができます.
最適化の第2歩:すべてのJOINを除去して、MySQLに自分で決定させます!こんなにびっしり書かれたleft join/inner joinは楽しかったですか?
explain
SELECT mb.id……
FROM mb,mbei,u
WHERE
mb.id=mbei.mb_id
and mb.uid=u.user_id
order by mbei.apply_time desc
limit 0,10
すぐに現れ、駆動表は同じ小表mbeiです.
最後のまとめ:
強調して強調する.
1、運を信じすぎないように!
2、あなたの開発環境のSQLの実行速度を信じないでください!
3、explain武器を取ってください.以下の現象を見たら、最適化してください.
1)Using temporaryが出現
2)rowsが多すぎたり、ほぼ全テーブルのレコード数
3)key Yes(NULL)
4)possible_keysインデックスが多すぎる(選択される)
覚えておいて、explainは美徳です!