SlideShare ist ein Scribd-Unternehmen logo
1 von 91
Downloaden Sie, um offline zu lesen
MicroAd
マイクロアド
薮下 和弥システム開発部
MySQL 勉強会
クエリチューニング編
はじめに
こんな考え方をしていませんか?
喝
当勉強会で…
これらの考え方が変わり、
クエリチューニングの見解が広がります!
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
1章 対話的にクエリを作る
City:都市テーブル
+-------------+------------+----------+------+-----+
| ColumnID | ColumnName | Type | Null | Key |
+-------------+------------+----------+------+-----+
| ID | 都市ID | int(11) | NO | PRI |
| Name | 都市名 | char(35) | NO | |
| CountryCode | 国コード | char(3) | NO | MUL |
| District | 地区 | char(20) | NO | |
| Population | 都市人口 | int(11) | NO | MUL |
+-------------+------------+----------+------+-----+
+----------------+------------------+---------------------------------------------------------------------------------------+------+-----+
| ColumnID | ColumnName | Type | Null | Key |
+----------------+------------------+---------------------------------------------------------------------------------------+------+-----+
| Code | 国コード | char(3) | NO | PRI |
| Name | 国名 | char(52) | NO | |
| Continent | 大陸 | enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') | NO | |
| Region | 地帯 | char(26) | NO | |
| SurfaceArea | 国土面積 | float(10,2) | NO | |
| IndepYear | 独立年 | smallint(6) | YES | |
| Population | 国人口 | int(11) | NO | |
| LifeExpectancy | 平均寿命 | float(3,1) | YES | |
| GNP | 国民総生産 | float(10,2) | YES | |
| GNPOld | 国民総生産(過去) | float(10,2) | YES | |
| LocalName | 国名(ローカル) | char(45) | NO | |
| GovernmentForm | 政治体系 | char(45) | NO | |
| HeadOfState | 国家元首 | char(60) | YES | |
| Capital | 首都コード | int(11) | YES | |
| Code2 | 国コード(略) | char(2) | NO | |
+----------------+------------------+---------------------------------------------------------------------------------------+------+-----+
Country:国テーブル
件数:4079
件数:239
当勉強会ではMySQLのサンプルデータベース内のテーブルを使用し、
実際にクエリを組んで見解を広げて頂きます。
Code
・
・
Country
・
CountryCode
・
City
Population / 2
+------------+
| Population |
+------------+
| 4848150 |
| 3990115 |
| 4990810 |
+------------+
1章 対話的にクエリを作る
抽出項目
都市名
国コード
都市人口
都市人口の半数が、
瀋陽の人口よりも多い都市
抽出条件
クエリ
SELECT
Cty1.Name,
Cty1.CountryCode,
Cty1.Population
FROM City Cty1
WHERE Cty.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.Name = 'Shenyang'
);
City(都市テーブル)
+-------------+------------+----------+-----+
| ColumnID | ColumnName | Type | Key |
+-------------+------------+----------+-----+
| ID | 都市ID | int(11) | PRI |
| Name | 都市名 | char(35) | |
| CountryCode | 国コード | char(3) | MUL |
| District | 地区 | char(20) | |
| Population | 都市人口 | int(11) | MUL |
+-------------+------------+----------+-----+
テーブル
抽出イメージ
Cty1(City)
+------+----------+-------------+----------+------------+
| ID | Name | CountryCode | District | Population |
+------+----------+-------------+----------+------------+
| 1890 | Shanghai | CHN | Shanghai | 9696300 |
| 1532 | Tokyo | JPN | Tokyo-to | 7980230 |
| 2331 | Seoul | KOR | Seoul | 9981620 |
+------+----------+-------------+----------+------------+
瀋陽の人口
+------------+
| Population |
+------------+
| 4265200 |
+------------+
Cty1(City)
+------+----------+-------------+----------+------------+
| ID | Name | CountryCode | District | Population |
+------+----------+-------------+----------+------------+
| 1890 | Shanghai | CHN | Shanghai | 9696300 |○
| 1532 | Tokyo | JPN | Tokyo-to | 7980230 |
| 2331 | Seoul | KOR | Seoul | 9981620 |○
+------+----------+-------------+----------+------------+
Cty1(City)
+------+----------+-------------+----------+------------+
| ID | Name | CountryCode | District | Population |
+------+----------+-------------+----------+------------+
| 1890 | Shanghai | CHN | Shanghai | 9696300 |○
| 1532 | Tokyo | JPN | Tokyo-to | 7980230 |
| 2331 | Seoul | KOR | Seoul | 9981620 |○
+------+----------+-------------+----------+------------+
Population / 2
+------------+
| Population |
+------------+
| 4848150 |
| 3990115 |
| 4990810 |
+------------+
1章 対話的にクエリを作る
完?
+----------+-------------+------------+
| Name | CountryCode | Population |
+----------+-------------+------------+
| Shanghai | CHN | 9696300 |
| Seoul | KOR | 9981620 |
+----------+-------------+------------+
実 行 結 果
1章 対話的にクエリを作る
ちょっと待った
速いの?
こ
の
ク
エ
リ
1章 対話的にクエリを作る
mysql> SELECT … WHERE Cty2.Name = 'Shenyang');
・
・
・
8 rows in set (0.00 sec)
速いッ!
1章 対話的にクエリを作る
…それだけでは駄目です。
実行計画を取得してください。
1章 対話的にクエリを作る
実行計画とは、
問い合わせ情報(クエリ)を基に、MySQLが内部的に立てる実行の計画(手順)です。
※MySQL 5.6からUPDATE、DELETE、INSERTも実行計画取得が可能
EXPLAIN select_query;
実行計画取得コマンド
言わば、
なのです。
MySQLの意思表示
1章 対話的にクエリを作る
先程作成したクエリの実行計画を確認してみましょう。
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
EXPLAIN SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.Name = 'Shenyang'
);
クエリ
実行計画
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
INDEXが使われてない!テーブルスキャン!!
外部クエリ
サブクエリ
1章 対話的にクエリを作る
何がダメなの? |ω・)
1章 対話的にクエリを作る
例えばこんなクエリ。
SELECT * FROM City WHERE Name = 'Tokyo'; City(都市テーブル) 件数:4079
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
row75
row1
row1001
row561
row314
row245
row843
row48
row1831 row181row468
row188
row2188
row821
row87
row987
row456
row6
row236
row4000
row813
row3
row30
row209
row131
row2430
row2120
row21
row2901
row333
row713
row3557
row1684
row338
row3388
row1088
row10
row1540
row3140row1059
row193
row412
row198
row15
row681
row1926
row1985
row2792
row961
row461
row1563
row3154
row1863
row731
row462
row1462
row3311
row1991
row1535
row501
row852
row3841
row100
row1091
row491
row481
row584
row522
row521
row64
row487
row983
row1616
row3731
City
row737
row1379
row3838
row1103
row588
row519
row819
row4009
row12
Cityの行を一つ一つを確認して、Nameが'Tokyo'の行を探してください。
1章 対話的にクエリを作る
これが、テーブルスキャン。
1章 対話的にクエリを作る
INDEXを付けるとどうなるの? |ω・)
1章 対話的にクエリを作る
SELECT * FROM City WHERE Name = 'Tokyo'; City(都市テーブル) 件数:4079
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | MUL |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
row1863
City
NameカラムのINDEX情報
'Tokyo'
A - K
L - Z
A - D
E - G
H - I
L - O
P - R
S - Z
Peking
Pusan
Qazvin
Rotterdam
Roma
London
Liverpool
Mexico
New York
Okinawa
Sydney
Tokyo
Washington
Valera
Zelenograd
… … …
A - K
L - Z
L - O
P - R
S - Z
Sydney
Tokyo
Washington
Valera
Zelenograd
1章 対話的にクエリを作る
これが、INDEXッ!!
+-------------+------------+----------+------+-----+
| ColumnID | ColumnName | Type | Null | Key |
+-------------+------------+----------+------+-----+
| ID | 都市ID | int(11) | NO | PRI |
| Name | 都市名 | char(35) | NO | |
| CountryCode | 国コード | char(3) | NO | MUL |
| District | 地区 | char(20) | NO | |
| Population | 都市人口 | int(11) | NO | MUL |
+-------------+------------+----------+------+-----+
1章 対話的にクエリを作る
MySQLには是非INDEXを使って頂きたい。
サブクエリからチューニングしてみます。
都市人口の半分が瀋陽の人口よりも多い都市
抽出仕様
City:都市テーブル
+-------------+------------+----------+------+-----+
| ColumnID | ColumnName | Type | Null | Key |
+-------------+------------+----------+------+-----+
| ID | 都市ID | int(11) | NO | PRI |
| Name | 都市名 | char(35) | NO | |
| CountryCode | 国コード | char(3) | NO | MUL |
| District | 地区 | char(20) | NO | |
| Population | 都市人口 | int(11) | NO | MUL |
+-------------+------------+----------+------+-----+
サブクエリ
SELECT
Cty1.Name,
Cty1.CountryCode,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.Name = 'Shenyang'
);
都市人口の半分が中国の瀋陽の人口よりも多い都市
瀋陽が中国の都市であることは明確であり、
抽出条件に国コードが追加されても問題はない。
SELECT
Cty1.Name,
Cty1.CountryCode,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE
AND Cty2.Name = 'Shenyang'
);
SELECT
Cty1.Name,
Cty1.CountryCode,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
);
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
1章 対話的にクエリを作る
修正後の実行計画は…
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
);
クエリ
チューニング前の実行計画
サブクエリの検索条件にCountryCodeを指定した
ことで、INDEXを利用した検索が可能に!
チューニング後の実行計画
1章 対話的にクエリを作る
次は外部クエリ。
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
City:都市テーブル
+-------------+------------+----------+------+-----+
| ColumnID | ColumnName | Type | Null | Key |
+-------------+------------+----------+------+-----+
| ID | 都市ID | int(11) | NO | PRI |
| Name | 都市名 | char(35) | NO | |
| CountryCode | 国コード | char(3) | NO | MUL |
| District | 地区 | char(20) | NO | |
| Population | 都市人口 | int(11) | NO | MUL |
+-------------+------------+----------+------+-----+
クエリ
実行計画
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
);
あれ?!
INDEXは?!
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
);
+-------------+------------+----------+------+-----+
| ColumnID | ColumnName | Type | Null | Key |
+-------------+------------+----------+------+-----+
| ID | 都市ID | int(11) | NO | PRI |
| Name | 都市名 | char(35) | NO | |
| CountryCode | 国コード | char(3) | NO | MUL |
| District | 地区 | char(20) | NO | |
| Population | 都市人口 | int(11) | NO | MUL |
+-------------+------------+----------+------+-----+
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
1章 対話的にクエリを作る
WHERE句内をよく見てください。
クエリ
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
);
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
);
索引列に対して演算処理を行っている場合、
オプティマイザはINDEXを使用することが出来ないのです。
1章 対話的にクエリを作る
ではどうするか。
都市人口の半分が中国瀋陽の人口よりも多い都市
抽出仕様
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population / 2 > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
);
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
) * 2;
= 都市人口が中国瀋陽の倍の人口よりも多い都市
抽出の仕様に影響なし
クエリ
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where |
+----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
1章 対話的にクエリを作る
修正後の実行計画は…
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
| 1 | PRIMARY | Cty1 | range | Population | Population | 4 | NULL | 8 | Using where |
| 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | | 363 | Using where |
+----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population > (
SELECT
Cty2.Population
FROM City Cty2
WHERE Cty2.CountryCode = 'CHN'
AND Cty2.Name = 'Shenyang'
) * 2;
クエリ
クエリチューニング前実行計画
索引列の演算処理を、右辺に移すことで
INDEXを利用した範囲検索が可能に!
クエリチューニング後実行計画
1章 対話的にクエリを作る
仕上げの実行結果確認
+----------+-------------+------------+
| Name | CountryCode | Population |
+----------+-------------+------------+
| Shanghai | CHN | 9696300 |
| Seoul | KOR | 9981620 |
+----------+-------------+------------+
実 行 結 果
1章 対話的にクエリを作る
ちなみに・・・
1章 対話的にクエリを作る
索引列を指定しても、オプティマイザがINDEXを
使用できないパターンは他にも存在します。
WHERE Index_Column IS NULL
NULL述語を使用
WHERE SUBSTRING(Index_Column, 1, 3) = 'abc'
SQL関数を使用
WHERE Index_Column <> 'abc'
否定形での条件指定
WHERE Index_Column = 'abc' OR Index_Column = 'def'
ORでの条件指定(INへの置き換えで対応可)
WHERE Index_Column LIKE '%abc%'
中間一致、後方一致でのLIKE述語を使用(前方一致は使用可能)
・
・
・
1章 まとめ
クエリ作成後は、必ず実行計画を取得すること!
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
2章 オプティマイザの判断
人口が400000人超えの都市 都市名
都市人口
SELECT Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000;
抽出条件 抽出項目
クエリテーブル
City(都市テーブル)
+-------------+------------+----------+-----+
| ColumnID | ColumnName | Type | Key |
+-------------+------------+----------+-----+
| ID | 都市ID | int(11) | PRI |
| Name | 都市名 | char(35) | |
| CountryCode | 国コード | char(3) | MUL |
| District | 地区 | char(20) | |
| Population | 都市人口 | int(11) | MUL |
+-------------+------------+----------+-----+
抽出イメージ
Cty
+------+------------+-------------+----------------+------------+
| ID | Name | CountryCode | District | Population |
+------+------------+-------------+----------------+------------+
| 135 | Canberra | AUS | Capital Region | 322723 |
| 1570 | Gifu | JPN | Gifu | 408007 |
| 1822 | Ottawa | CAN | Ontario | 335277 |
| 2318 | Pyongyang | PRK | Pyongyang-si | 2484000 |
| 3209 | Bratislava | SVK | Bratislava | 448292 |
| 3831 | Atlanta | USA | Georgia | 416474 |
+------+------------+-------------+----------------+------------+
Cty
+------+------------+-------------+----------------+------------+
| ID | Name | CountryCode | District | Population |
+------+------------+-------------+----------------+------------+
| 135 | Canberra | AUS | Capital Region | 322723 |
| 1570 | Gifu | JPN | Gifu | 408007 |○
| 1822 | Ottawa | CAN | Ontario | 335277 |
| 2318 | Pyongyang | PRK | Pyongyang-si | 2484000 |○
| 3209 | Bratislava | SVK | Bratislava | 448292 |○
| 3831 | Atlanta | USA | Georgia | 416474 |○
+------+------------+-------------+----------------+------------+
Cty
+------+------------+-------------+----------------+------------+
| ID | Name | CountryCode | District | Population |
+------+------------+-------------+----------------+------------+
| 135 | Canberra | AUS | Capital Region | 322723 |
| 1570 | Gifu | JPN | Gifu | 408007 |○
| 1822 | Ottawa | CAN | Ontario | 335277 |
| 2318 | Pyongyang | PRK | Pyongyang-si | 2484000 |○
| 3209 | Bratislava | SVK | Bratislava | 448292 |○
| 3831 | Atlanta | USA | Georgia | 416474 |○
+------+------------+-------------+----------------+------------+
2章 オプティマイザの判断
今回はイケる気がする (`・ω ・´)
2章 オプティマイザの判断
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
EXPLAIN SELECT Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000;
…あれっ!?
実行計画
実行計画は…
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
2章 オプティマイザの判断
possible_keysを見てください。
INDEX「Population」は使える状況であることがわかります。
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
| 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+------+-------------+
※1章のチューニング前の実行計画
2章 オプティマイザの判断
では、なぜ?
2章 オプティマイザの判断
オプティマイザがINDEXを使用するよりも、
テーブルスキャンをした方が効率が良いと判断したのです。
※取得するデータの量が表全体の5%~15%以下(目安)の場合にインデックスを使用
2章 オプティマイザの判断
試しに人口600000人超え(表全体の約10%)の都市を抽出してみます。
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
| 1 | SIMPLE | Cty | range | Population | Population | 4 | NULL | 428 | Using where |
+----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+
EXPLAIN SELECT Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 600000;
この条件の場合は、INDEXを利用した方が効率が良いと判断したようです。
実行計画
2章 まとめ
INDEXを使えないのか、使わないのか。
適切に判断し、適切にアプローチを。
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
3章 サブクエリは「データ」の集合
SELECT
Ctr.Name CountryName,
Sub.Name CityName,
Sub.Population
FROM Country Ctr
LEFT JOIN (
SELECT
Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000
) Sub
ON Ctr.Code = Sub.CountryCode;
City(都市テーブル)
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
Country(国テーブル)
+----------+---------------+-----+
| ColumnID | ColumnName | Key |
+----------+---------------+-----+
| Code | 国コード | PRI |
| Name | 国名 | |
==============省略================
全ての国名の一覧を表示。
各国に人口が400000人以上の都市が存在する場合、
その各都市の名称と人口の情報を付与する。
存在しない場合はNULLを表示する。
国名
都市名
都市人口
抽出条件 抽出項目
クエリテーブル
抽出イメージ
Ctr
+------+---------------+
| Code | Name |
+------+---------------+
| JPN | Japan |
| KOR | South Korea |
| SVK | Slovakia |
| USA | United States |
+------+---------------+
Cty
+------------+-------------+------------+
| Name | CountryCode | Population |
+------------+-------------+------------+
| Gifu | JPN | 408007 |
| Pyongyang | PRK | 2484000 |
| Bratislava | SVK | 448292 |
| Atlanta | USA | 416474 |
+------------+-------------+------------+
Ctr LEFT JOIN Sub
+---------------+------------+------------+
| CountryName | CityName | Population |
+---------------+------------+------------+
| Japan | Gifu | 408007 |
| South Korea | NULL | NULL |
| Slovakia | Bratislava | 448292 |
| United States | Atlanta | 416474 |
+---------------+------------+------------+
Sub
+------------+-------------+------------+
| Name | CountryCode | Population |
+------------+-------------+------------+
| Gifu | JPN | 408007 |○
| Pyongyang | PRK | 2484000 |
| Bratislava | SVK | 448292 |○
| Atlanta | USA | 416474 |○
+------------+-------------+------------+
+ =
3章 サブクエリは「データ」の集合
クエリの実行計画を確認してみます。
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | |
| 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
EXPLAIN SELECT
Ctr.Name CountryName,
Sub.Name CityName,
Sub.Population
FROM Country Ctr
LEFT JOIN (
SELECT
Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000
) Sub
ON Ctr.Code = Sub.CountryCode;
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | |
| 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
結合キーとして、
INDEXが使われていません。
実行計画
derived2
3章 サブクエリは「データ」の集合
図解するとこんな感じです。
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | |
| 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
Cty
PK
INDEX
Ctr
サブクエリにて抽出した集合には
PKやINDEXの情報は含まれない。
Ctrを基準にderived2とJOIN
PK
INDEX
※基準になるテーブルのINDEXは使われません。
3章 サブクエリは「データ」の集合
ちょっと、振り返ります。
3章 サブクエリは「データ」の集合
SELECT
Ctr.Name CountryName,
Sub.Name CityName,
Sub.Population
FROM Country Ctr
LEFT JOIN (
SELECT
Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000
) Sub
ON Ctr.Code = Sub.CountryCode;
City(都市テーブル)
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
Country(国テーブル)
+----------+---------------+-----+
| ColumnID | ColumnName | Key |
+----------+---------------+-----+
| Code | 国コード | PRI |
| Name | 国名 | |
==============省略================
クエリテーブル
抽出イメージ
Ctr
+------+---------------+
| Code | Name |
+------+---------------+
| JPN | Japan |
| KOR | South Korea |
| SVK | Slovakia |
| USA | United States |
+------+---------------+
Cty
+------------+-------------+------------+
| Name | CountryCode | Population |
+------------+-------------+------------+
| Gifu | JPN | 408007 |
| Pyongyang | PRK | 2484000 |
| Bratislava | SVK | 448292 |
| Atlanta | USA | 416474 |
+------------+-------------+------------+
Ctr LEFT JOIN Sub
+---------------+------------+------------+
| CountryName | CityName | Population |
+---------------+------------+------------+
| Japan | Gifu | 408007 |
| South Korea | NULL | NULL |
| Slovakia | Bratislava | 448292 |
| United States | Atlanta | 416474 |
+---------------+------------+------------+
Sub
+------------+-------------+------------+
| Name | CountryCode | Population |
+------------+-------------+------------+
| Gifu | JPN | 408007 |○
| Pyongyang | PRK | 2484000 |
| Bratislava | SVK | 448292 |○
| Atlanta | USA | 416474 |○
+------------+-------------+------------+
+ =
Countryテーブルと結合するのはCityテーブルではなく、
あくまでもSubというデータの集合(テンポラリテーブル)
3章 サブクエリは「データ」の集合
ではどうするか。
SELECT
Ctr.Name CountryName,
Sub.Name CityName,
Sub.Population
FROM Country Ctr
LEFT JOIN
(SELECT
Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000
) Sub
ON Ctr.Code = Sub.CountryCode;
SELECT
Ctr.Name CountryName,
Cty.Name CityName,
Cty.Population
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode;
クエリ
SELECT
Ctr.Name CountryName,
Cty.Name CityName,
Cty.Population
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode
AND Cty.Population > 400000;
Ctr
+------+---------------+
| Code | Name |
+------+---------------+
| JPN | Japan |
| KOR | South Korea |
| SVK | Slovakia |
| USA | United States |
+------+---------------+
Cty
+------------+-------------+------------+
| Name | CountryCode | Population |
+------------+-------------+------------+
| Gifu | JPN | 408007 |
| Kwangmyong | KOR | 350914 |
| Pyongyang | PRK | 2484000 |
| Bratislava | SVK | 448292 |
| Atlanta | USA | 416474 |
+------------+-------------+------------+
Ctr LEFT JOIN Cty
+---------------+------------+------------+
| CountryName | CityName | Population |
+---------------+------------+------------+
| Japan | Gifu | 408007 |
| South Korea | Kwangmyong | 350914 |
| Slovakia | Bratislava | 448292 |
| United States | Atlanta | 416474 |
+---------------+------------+------------+
+ =
抽出イメージ
City(都市テーブル)
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
Country(国テーブル)
+----------+---------------+-----+
| ColumnID | ColumnName | Key |
+----------+---------------+-----+
| Code | 国コード | PRI |
| Name | 国名 | |
==============省略================
テーブル
Cty
+------------+-------------+------------+
| Name | CountryCode | Population |
+------------+-------------+------------+
| Gifu | JPN | 408007 |
| Kwangmyong | KOR | 350914 |
| Pyongyang | PRK | 2484000 |
| Bratislava | SVK | 448292 |
| Atlanta | USA | 416474 |
+------------+-------------+------------+
Ctr LEFT JOIN Cty
+---------------+------------+------------+
| CountryName | CityName | Population |
+---------------+------------+------------+
| Japan | Gifu | 408007 |
| South Korea | NULL | NULL |
| Slovakia | Bratislava | 448292 |
| United States | Atlanta | 416474 |
+---------------+------------+------------+
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | |
| 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
3章 サブクエリは「データ」の集合
修正後の実行計画は…
+----+-------------+-------+------+------------------------+-------------+---------+----------------+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+------------------------+-------------+---------+----------------+------+-------+
| 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | |
| 1 | SIMPLE | Cty | ref | CountryCode,Population | CountryCode | 3 | world.Ctr.Code | 7 | |
+----+-------------+-------+------+------------------------+-------------+---------+----------------+------+-------+
EXPLAIN SELECT
Ctr.Name CountryName,
Cty.Name CityName,
Cty.Population
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode
AND Cty.Population > 400000;
クエリ
サブクエリを使わず直接テーブル同士をJOINしたことで、
INDEXを利用したJOINが可能に!
クエリチューニング前実行計画クエリチューニング後実行計画
3章 サブクエリは「データ」の集合
ちなみに・・・
3章 サブクエリは「データ」の集合
チューニング前のクエリの結合方式を内部結合にすると…
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
| 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | |
| 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+------------+------+---------------+------+---------+------+------+-------------+
EXPLAIN SELECT
Ctr.Name CountryName,
Sub.Name CityName,
Sub.Population
FROM Country Ctr
LEFT JOIN (
SELECT
Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000
) Sub
ON Ctr.Code = Sub.CountryCode;
EXPLAIN SELECT
Ctr.Name CountryName,
Sub.Name CityName,
Sub.Population
FROM Country Ctr
INNER JOIN (
SELECT
Cty.CountryCode,
Cty.Name,
Cty.Population
FROM City Cty
WHERE Cty.Population > 400000
) Sub
ON Ctr.Code = Sub.CountryCode;
+----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | |
| 1 | PRIMARY | Ctr | eq_ref | PRIMARY | PRIMARY | 3 | Sub.CountryCode | 1 | |
| 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+
INDEXが…
使われている!?
実行計画
3章 サブクエリは「データ」の集合
図で説明します
+----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | |
| 1 | PRIMARY | Ctr | eq_ref | PRIMARY | PRIMARY | 3 | Sub.CountryCode | 1 | |
| 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where |
+----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+
Cty
PK
INDEX
derived2 Ctr
derived2を基準にCtrとJOIN
内部結合の場合、どちらを基準にしても良いため、
オプティマイザが効率的と判断した集合を基準に結合する。
サブクエリにて抽出した集合には
PKやINDEXの情報は含まれていない。
PK
PK
INDEX
3章 まとめ
サブクエリで抽出した集合にはINDEXは無い!
サブクエリを結合する場合は、
サブクエリ内で十分にデータを絞り込むか、
別の抽出方法を検討すること。
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
4章 ソートとインデックス
全ての国名とその国が所有する都市数
クエリ
SELECT
Ctr.Code CountryCode,
Ctr.Name CountryName,
COUNT(Cty.ID) CityCount
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode
GROUP BY Ctr.Code,
Ctr.Name;
抽出仕様 抽出項目
国コード
国名
都市数
City(都市テーブル)
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
Country(国テーブル)
+----------+---------------+-----+
| ColumnID | ColumnName | Key |
+----------+---------------+-----+
| Code | 国コード | PRI |
| Name | 国名 | |
==============省略================
テーブル
抽出イメージ
Ctr
+------+---------------+
| Code | Name |
+------+---------------+
| ATA | Antarctica |
| JPN | Japan |
| KOR | South Korea |
| USA | United States |
+------+---------------+
Cty
+------+----------+-------------+
| ID | Name | CountryCode |
+------+----------+-------------+
| 129 | Aruba | ABW |
| 1532 | Tokyo | JPN |
| 1534 | Osaka | JPN |
| 2331 | Seoul | KOR |
| 3793 | New York | USA |
+------+----------+-------------+
Ctr LEFT JOIN Cty
+------+---------------+------+----------+-------------+
| Code | Name | ID | Name | CountryCode |
+------+---------------+------+----------+-------------+
| ATA | Antarctica | NULL | NULL | NULL |
| JPN | Japan | 1532 | Tokyo | JPN |
| JPN | Japan | 1534 | Osaka | JPN |
| KOR | South Korea | 2331 | Seoul | KOR |
| USA | United States | 3793 | New York | USA |
+------+---------------+------+----------+-------------+
+ =
Ctr LEFT JOIN Cty GROUP BY Ctr.Column
+-------------+---------------+-----------+
| CountryCode | CountryName | CityCount |
+-------------+---------------+-----------+
| ATA | Antarctica | 0 |
| JPN | Japan | 2 |
| KOR | South Korea | 1 |
| USA | United States | 1 |
+-------------+---------------+-----------+
Cty
+------+----------+-------------+
| ID | Name | CountryCode |
+------+----------+-------------+
| 129 | Aruba | ABW |
| 1532 | Tokyo | JPN |○
| 1534 | Osaka | JPN |○
| 2331 | Seoul | KOR |○
| 3793 | New York | USA |○
+------+----------+-------------+
4章 ソートとインデックス
SELECT
Ctr.Code CountryCode,
Ctr.Name CountryName,
COUNT(Cty.ID) CityCount
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode
GROUP BY Ctr.Code,
Ctr.Name;
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort |
| 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
テーブルの結合キーに関してはINDEXが使われていますが、
今回注目して頂きたいのは結合基準となるテーブルのExtraフィールドです。
クエリの実行計画を確認してみます。
実行計画
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort |
| 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort |
| 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
4章 ソートとインデックス
図解するとこんな感じ。
Ctr
Ctr1
Ctr2
Ctr3
Ctr4
Cty
Cty1-1
Cty3-1
Cty2-2
Cty2-1
Cty4-1
テンポラリテーブル
LEFT
JOIN
SORT
出力
Ctr1
Ctr2
Ctr3
Ctr4
Cty2-1
Cty2-2
Cty3-1
Cty4-1
Ctr1
Ctr2
Ctr3
Ctr4
Cty3-1
Cty2-2
Cty2-1
Cty4-1
Ctr
+------+---------------+
| Code | Name |
+------+---------------+
| USA | United States |4
| JPN | Japan |2
| ATA | Antarctica |1
| KOR | South Korea |3
+------+---------------+
Cty
+----------+-------------+
| Name | CountryCode |
+----------+-------------+
| Osaka | JPN |2-2
| Seoul | KOR |3-1
| Aruba | ABW |1-1
| New York | USA |4-1
| Tokyo | JPN |2-1
+----------+-------------+
Ctr LEFT JOIN Cty GROUP BY Ctr.Columns
+-------------+---------------+-----------+
| CountryCode | CountryName | CityCount |
+-------------+---------------+-----------+
| ATA | Antarctica | 0 |
| JPN | Japan | 2 |
| KOR | South Korea | 1 |
| USA | United States | 1 |
+-------------+---------------+-----------+
テ
ン
ポ
ラ
リ
テ
ー
ブ
ル
Using temporary Using filesort
4章 ソートとインデックス
Ctr
Ctr1
Ctr2
Ctr3
Ctr4
Cty
Cty1-1
Cty3-1
Cty2-2
Cty2-1
Cty4-1
テンポラリテーブル
LEFT
JOIN
SORT
出力
Ctr1
Ctr2
Ctr3
Ctr4
Cty2-1
Cty2-2
Cty3-1
Cty4-1
Ctr1
Ctr2
Ctr3
Ctr4
Cty3-1
Cty2-2
Cty2-1
Cty4-1
Ctr
+------+---------------+
| Code | Name |
+------+---------------+
| USA | United States |4
| JPN | Japan |2
| ATA | Antarctica |1
| KOR | South Korea |3
+------+---------------+
Cty
+----------+-------------+
| Name | CountryCode |
+----------+-------------+
| Tokyo | JPN |2-2
| Seoul | KOR |3-1
| Aruba | ABW |1-1
| New York | USA |4-1
| Osaka | JPN |2-1
+----------+-------------+
Ctr LEFT JOIN Cty GROUP BY Ctr_Column
+-------------+---------------+-----------+
| CountryCode | CountryName | CityCount |
+-------------+---------------+-----------+
| ATA | Antarctica | 0 |
| JPN | Japan | 2 |
| KOR | South Korea | 1 |
| USA | United States | 1 |
+-------------+---------------+-----------+
テ
ン
ポ
ラ
リ
テ
ー
ブ
ル
Using temporary Using filesort
実はこいつら、やっつけられます。
4章 ソートとインデックス
対応方法の一つとして複合INDEXを用いる方法があります。
SELECT
Ctr.Code CountryCode,
Ctr.Name CountryName,
COUNT(Cty.ID) CityCount
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode
GROUP BY Ctr.Code,
Ctr.Name;
上記クエリのGROUP BY句にて使用する集計キーに対して、
下記のコマンドで複合INDEXを貼ります。
ALTER TABLE Country ADD INDEX mul_idx1(Code, Name);
4章 ソートとインデックス
複合INDEX対応後のクエリの実行計画を確認してみます。
SELECT
Ctr.Code CountryCode,
Ctr.Name CountryName,
COUNT(Cty.ID) CityCount
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode
GROUP BY Ctr.Code,
Ctr.Name;
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
| 1 | SIMPLE | Ctr | index | NULL | mul_idx1 | 55 | NULL | 1 | Using index |
| 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index |
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
+---------+----------+--------------+-------------+
| Table | Key_name | Seq_in_index | Column_name |
+---------+----------+--------------+-------------+
| Country | PRIMARY | 1 | Code |
| Country | mul_idx1 | 1 | Code |
| Country | mul_idx1 | 2 | Name |
+---------+----------+--------------+-------------+
実行計画
複合INDEXを貼ることによって、
INDEXを用いたソートが可能に!
4章 ソートとインデックス
そもそも、ソートにINDEXを使うってどういうこと?
4章 ソートとインデックス
mul_idx1(Code, Name)のINDEX情報
head
AAA CCC
333 333
BBB
222 222111 111
Code
Name
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨
複合INDEXは下記図のようなINDEX情報となります。
INDEXとして保持している情報はCode、Nameの順にソートされています。
つまりINDEX順に行を取り出したその時、既にソートは終わっているのです。
4章 ソートとインデックス
Ctr
Ctr1
Ctr2
Ctr3
Ctr4
Cty
Cty1-1
Cty3-1
Cty2-2
Cty2-1
Cty4-1
LEFT
JOIN
SORT
出力
Ctr1
Ctr2
Ctr3
Ctr4
Cty2-1
Cty2-2
Cty3-1
Cty4-1
Ctr1
Ctr2
Ctr3
Ctr4
Cty3-1
Cty2-2
Cty2-1
Cty4-1
Using temporary Using filesort
つまりこういうこと。
INDEX情報
データ抽出
Ctr
LEFT JOIN
4章 ソートとインデックス
Codeのみの単一INDEXではだめなの?
4章 ソートとインデックス
CodeのみのINDEX情報
head
AAA CCCBBBCode
①
単一INDEXは下記図のようなINDEX情報となります。
② ③
上の図だけでダメなのはわかりますね。
インデックス順にデータを取得しても、Name列はソートされていない状態です。
4章 ソートとインデックス
複合INDEXの定義順を逆にするとどうなるの?
4章 ソートとインデックス
mul_idx1(Name, Code)のINDEX情報
head
1 3
CCDCCC CCE
2
BBCBBB BBDAABAAA AAC
Name
Code
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨
複合INDEXの定義順を逆にしてみます。
SELECT
Ctr.Code CountryCode,
Ctr.Name CountryName,
COUNT(Cty.ID) CityCount
FROM Country Ctr
LEFT JOIN City Cty
ON Ctr.Code = Cty.CountryCode
GROUP BY Ctr.Code,
Ctr.Name;
クエリ
INDEX情報はName、Codeの順でソートされています。
よって、INDEX順でデータを取得したとしても、
Code、Name順にソートする必要が出てきます。
4章 ソートとインデックス
他にも色々あるので、この情報を基にいろいろ調べてみてください。
4章 ソートとインデックス
68
実は・・・
4章 ソートとインデックス
当件、新たにINDEXを付けなくてもINDEX付与後以上の
パフォーマンスにチューニングすることが可能です。
次章で説明します。
4章 まとめ
GROUP BY、ORDER BYでも
インデックスの利用を意識すること!
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
5章 インデックスは万能ではない
4章で例に挙げたクエリの実際の実行時間は以下です。
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
| 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort |
| 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index |
+----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
複合INDEX付与前
複合INDEX付与後
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
| 1 | SIMPLE | Ctr | index | NULL | mul_idx1 | 55 | NULL | 1 | Using index |
| 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index |
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
実行時間
239 rows in set (0.26 sec)
実行時間
239 rows in set (0.59 sec)
※データ量増
5章 インデックスは万能ではない
クエリ
抽出仕様 抽出項目
国コード
国名
都市数
City(都市テーブル) (件数増幅:411979)
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
Country(国テーブル)
+----------+---------------+-----+
| ColumnID | ColumnName | Key |
+----------+---------------+-----+
| Code | 国コード | PRI |
| Name | 国名 | |
==============省略================
テーブル
抽出イメージ
Ctr
+------+---------------+
| Code | Name |
+------+---------------+
| ATA | Antarctica |
| JPN | Japan |
| KOR | South Korea |
| USA | United States |
+------+---------------+
Cty
+-------------+-----------+
| CountryCode | CityCount |
+-------------+-----------+
| ABW | 2 |
| JPN | 2 |
| KOR | 1 |
| USA | 1 |
+-------------+-----------+
Ctr LEFT JOIN Sub GROUP BY Ctr_Column
+-------------+---------------+-----------+
| CountryCode | CountryName | CityCount |
+-------------+---------------+-----------+
| ATA | Antarctica | 0 |
| JPN | Japan | 2 |
| KOR | South Korea | 1 |
| USA | United States | 1 |
+-------------+---------------+-----------+
+ =
SELECT
Ctr.Code CountryCode,
Ctr.Name CountryName,
IFNULL(Sub.CityCount, 0) CityCount
FROM Country Ctr
LEFT JOIN (
SELECT
Cty.CountryCode,
COUNT(*) CityCount
FROM City Cty
GROUP BY Cty.CountryCode
) Sub
ON Ctr.Code = Sub.CountryCode;
Sub
+-------------+-----------+
| CountryCode | CityCount |
+-------------+-----------+
| ABW | 2 |
| JPN | 2 |○
| KOR | 1 |○
| USA | 1 |○
+-------------+-----------+
全ての国名とその国が所有する都市数
5章 インデックスは万能ではない
クエリの実行計画を確認してみます。
SELECT
Ctr.Code CountryCode,
Ctr.Name CountryName,
IFNULL(Sub.CityCount, 0) CityCount
FROM Country Ctr
LEFT JOIN (
SELECT
Cty.CountryCode,
COUNT(*) CityCount
FROM City Cty
GROUP BY Cty.CountryCode
) Sub
ON Ctr.Code = Sub.CountryCode;
+----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
| 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 245 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | |
| 2 | DERIVED | Cty | index | NULL | CountryCode | 3 | NULL | 412116 | Using index |
+----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
サブクエリのGROUP BYにて単一INDEXを集計キーとして使用!
※JOINがテーブルスキャンとなっているが負荷は軽微!
実行計画
5章 インデックスは万能ではない
複合インデックス付与版
クエリ作り直し版
+----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
| 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 245 | |
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | |
| 2 | DERIVED | Cty | index | NULL | CountryCode | 3 | NULL | 412116 | Using index |
+----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+
実行時間
239 rows in set (0.16 sec)
実行時間
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
| 1 | SIMPLE | Ctr | index | NULL | mul_idx1 | 55 | NULL | 1 | Using index |
| 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index |
+----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+
239 rows in set (0.26 sec)
5章 まとめ
安易にINDEXを貼る前に、
様々なチューニングパターンを検討すること!
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
6章 相関サブクエリは諸刃の剣
各国の最大人口を誇る都市を抽出
クエリ
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population = (
SELECT
MAX(Cty2.Population)
FROM City Cty2
WHERE Cty2.CountryCode = Cty1.CountryCode
);
City(都市テーブル) (件数増幅:411979)
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
抽出項目
国コード
都市名
都市人口
抽出仕様
テーブル
6章 相関サブクエリは諸刃の剣
クエリの実行計画を確認してみます。
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population = (
SELECT
MAX(Cty2.Population)
FROM City Cty2
WHERE Cty2.CountryCode = Cty1.CountryCode
);
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 412116 | Using where |
| 2 | DEPENDENT SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | world_big.Cty1.CountryCode | 873 | |
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
相関サブクエリで構成されているため、select_typeに
DEPENDENT SUBQUERYと表示されています。
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 412116 | Using where |
| 2 | DEPENDENT SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | world_big.Cty1.CountryCode | 873 | |
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
外部クエリ
サブクエリ
実行計画
6章 相関サブクエリは諸刃の剣
+-------------+--------------+------------+
| CountryCode | Name | Population |
+-------------+--------------+------------+
① | JPN | Tokyo | 7980230 |
② | JPN | Osaka | 2595674 |
③ | JPN | Kamakura | 167661 |
④ | CHN | Shanghai | 9696300 |
⑤ | CHN | Kunming | 1829500 |
⑥ | CHN | Dali | 136554 |
⑦ | USA | New York | 8008278 |
⑧ | USA | Houston | 1953631 |
⑨ | USA | Hollywood | 139357 |
+-------------+--------------+------------+
データの内容
相関サブクエリのイメージを図示すると以下のような感じです。
⑨
⑧
Cty1
②
①
⑥ ④
⑤
⑦ ③
Cty2
CountryCode=JPN CountryCode=CHN CountryCode=USA
+-------------+--------------+------------+
| CountryCode | Name | Population |
+-------------+--------------+------------+
① | JPN | Tokyo | 7980230 |
④ | CHN | Shanghai | 9696300 |
⑦ | USA | New York | 8008278 |
+-------------+--------------+------------+
クエリ実行結果
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population = ();
SELECT
MAX(Cty2.Population)
FROM City Cty2
WHERE Cty2.CountryCode = Cty1.CountryCode
Cty1.CountryCodeで
Cty2の集合を分割
MAX(Cty2.Population)
+-------------+--------------+------------+
| CountryCode | Name | Population |
+-------------+--------------+------------+
① | JPN | Tokyo | 7980230 |
② | JPN | Osaka | 2595674 |
③ | JPN | Kamakura | 167661 |
④ | CHN | Shanghai | 9696300 |
⑤ | CHN | Kunming | 1829500 |
⑥ | CHN | Dali | 136554 |
⑦ | USA | New York | 8008278 |
⑧ | USA | Houston | 1953631 |
⑨ | USA | Hollywood | 139357 |
+-------------+--------------+------------+
6章 相関サブクエリは諸刃の剣
テーブルアクセスイメージ
Cty2
Cty1
row2
row1
row412115
row412116
Cty2
Cty2
Cty2
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
| 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 412116 | Using where |
| 2 | DEPENDENT SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | world_big.Cty1.CountryCode | 873 | |
+----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+
実行計画
row1
row2
row412115
row412116
・
・
・
873件
スキャン
873件
スキャン
873件
スキャン
873件
スキャン
359,777,268件
スキャン!
412116件
スキャン
6章 相関サブクエリは諸刃の剣
82
Cty2
①SELECT 'Tokyo' , 'JPN' , 7980230 FROM City WHERE 7980230 = 7980230; ○
②SELECT 'Osaka' , 'JPN' , 2595674 FROM City WHERE 2595674 = 7980230;
③SELECT 'Kamakura' , 'JPN' , 167661 FROM City WHERE 167661 = 7980230;
④SELECT 'Shanghai' , 'CHN' , 9696300 FROM City WHERE 9696300 = 9696300; ○
⑤SELECT 'Kunming' , 'CHN' , 1829500 FROM City WHERE 1829500 = 9696300;
⑥SELECT 'Dali' , 'CHN' , 136554 FROM City WHERE 136554 = 9696300;
⑦SELECT 'New York' , 'USA' , 8008278 FROM City WHERE 8008278 = 8008278; ○
⑧SELECT 'Houston' , 'USA' , 1953631 FROM City WHERE 1953631 = 8008278;
⑨SELECT 'Hollywood' , 'USA' , 139357 FROM City WHERE 139357 = 8008278;
⑨
⑧
Cty1
②
①
⑥ ④
⑤
⑦ ③
+-------------+--------------+------------+
| CountryCode | Name | Population |
+-------------+--------------+------------+
① | JPN | Tokyo | 7980230 |
② | JPN | Osaka | 2595674 |
③ | JPN | Kamakura | 167661 |
④ | CHN | Shanghai | 9696300 |
⑤ | CHN | Kunming | 1829500 |
⑥ | CHN | Dali | 136554 |
⑦ | USA | New York | 8008278 |
⑧ | USA | Houston | 1953631 |
⑨ | USA | Hollywood | 139357 |
+-------------+--------------+------------+
データの内容
クエリ展開図
Cty1.CountryCode
MAX(Cty2.Population)
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
WHERE Cty1.Population = ();
SELECT
MAX(Cty2.Population)
FROM City Cty2
WHERE Cty2.CountryCode = Cty1.CountryCode
相関サブクエリの仕組み
Cty1のタプル数分、
Cty2のクエリ発行を
繰り返す
6章 相関サブクエリは諸刃の剣
実行結果 … 返ってきません。
チューニングしましょう。
6章 相関サブクエリは諸刃の剣
各国の最大人口を誇る都市を抽出
クエリ
City(都市テーブル) (件数増幅:411979)
+-------------+------------+-----+
| ColumnID | ColumnName | Key |
+-------------+------------+-----+
| ID | 都市ID | PRI |
| Name | 都市名 | |
| CountryCode | 国コード | MUL |
| District | 地区 | |
| Population | 都市人口 | MUL |
+-------------+------------+-----+
抽出項目
国コード
都市名
都市人口
抽出仕様
テーブル
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
INNER JOIN (
SELECT
Cty2.CountryCode,
MAX(Cty2.Population) Population
FROM City Cty2
GROUP BY Cty2.CountryCode
) Sub
ON Cty1.CountryCode = Sub.CountryCode
AND Cty1.Population = Sub.Population;
抽出イメージ
Cty1
+-------------+--------------+------------+
| CountryCode | Name | Population |
+-------------+--------------+------------+
| JPN | Tokyo | 7980230 |
| JPN | Osaka | 2595674 |
| JPN | Kamakura | 167661 |
| CHN | Shanghai | 9696300 |
| CHN | Kunming | 1829500 |
| CHN | Dali | 136554 |
| USA | New York | 8008278 |
| USA | Houston | 1953631 |
| USA | Hollywood | 139357 |
+-------------+--------------+------------+
Sub (Cty2)
+-------------+------------+
| CountryCode | Population |
+-------------+------------+
| JPN | 7980230 |
| CHN | 9696300 |
| USA | 8008278 |
+-------------+------------+
Cty1 INNER JOIN Sub
+-------------+--------------+------------+
| CountryCode | Name | Population |
+-------------+--------------+------------+
| JPN | Tokyo | 7980230 |
| CHN | Shanghai | 9696300 |
| USA | New York | 8008278 |
+-------------+--------------+------------+
+ =
Cty1
+-------------+--------------+------------+
| CountryCode | Name | Population |
+-------------+--------------+------------+
| JPN | Tokyo | 7980230 |
| JPN | Osaka | 2595674 |
| JPN | Kamakura | 167661 |
| CHN | Shanghai | 9696300 |
| CHN | Kunming | 1829500 |
| CHN | Dali | 136554 |
| USA | New York | 8008278 |
| USA | Houston | 1953631 |
| USA | Hollywood | 139357 |
+-------------+--------------+------------+
6章 相関サブクエリは諸刃の剣
クエリの実行計画を確認してみます。
SELECT
Cty1.CountryCode,
Cty1.Name,
Cty1.Population
FROM City Cty1
INNER JOIN (
SELECT
Cty2.CountryCode,
MAX(Cty2.Population) Population
FROM City Cty2
GROUP BY Cty2.CountryCode
) Sub
ON Cty1.CountryCode = Sub.CountryCode
AND Cty1.Population = Sub.Population;
+----+-------------+------------+-------+------------------------+-------------+---------+-------------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+------------------------+-------------+---------+-------------------+--------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | |
| 1 | PRIMARY | Cty1 | ref | CountryCode,Population | Population | 4 | Sub.Population | 1 | Using where |
| 2 | DERIVED | Cty2 | index | NULL | CountryCode | 3 | NULL | 412116 | |
+----+-------------+------------+-------+------------------------+-------------+---------+-------------------+--------+-------------+
実行時間は以下の通りです。
232 rows in set (0.76 sec)
6章 相関サブクエリは諸刃の剣
なんで速くなったの?
6章 相関サブクエリは諸刃の剣
テーブルアクセスイメージ
+----+-------------+------------+-------+------------------------+-------------+---------+----------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+------------+-------+------------------------+-------------+---------+----------------+--------+-------------+
| 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | |
| 1 | PRIMARY | Cty1 | ref | CountryCode,Population | Population | 4 | Sub.Population | 1 | Using where |
| 2 | DERIVED | Cty2 | index | NULL | CountryCode | 3 | NULL | 412116 | |
+----+-------------+------------+-------+------------------------+-------------+---------+----------------+--------+-------------+
チューニング後の実行計画
Cty1 Cty2
derived2
412116件
スキャン
232件
232 * 1件
スキャン
6章 まとめ
相関サブクエリは便利かつ、
それでしか実現できない抽出条件も存在する!
しかし、ボトルネックの温床!
1章 対話的にクエリを作る
2章 オプティマイザの判断
3章 サブクエリは「データ」の集合
4章 ソートとインデックス
5章 インデックスは万能ではない
6章 相関サブクエリは諸刃の剣
休憩
最後に
Microadの職人たちを紹介します。
※画像クリックでリンク先に遷移します。
2013年6月時点のサイトトップ
御清聴ありがとうございました

Weitere ähnliche Inhalte

Was ist angesagt?

統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)Takuto Wada
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターンSoudai Sone
 
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
行ロックと「LOG: process 12345 still waiting for ShareLock on transaction 710 afte...
行ロックと「LOG:  process 12345 still waiting for ShareLock on transaction 710 afte...行ロックと「LOG:  process 12345 still waiting for ShareLock on transaction 710 afte...
行ロックと「LOG: process 12345 still waiting for ShareLock on transaction 710 afte...Masahiko Sawada
 
MySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいことMySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいことyoku0825
 
世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)
世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)
世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニング雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニングyoku0825
 
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)Hironobu Suzuki
 
PostgreSQL 15の新機能を徹底解説
PostgreSQL 15の新機能を徹底解説PostgreSQL 15の新機能を徹底解説
PostgreSQL 15の新機能を徹底解説Masahiko Sawada
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Taku Miyakawa
 
まずやっとくPostgreSQLチューニング
まずやっとくPostgreSQLチューニングまずやっとくPostgreSQLチューニング
まずやっとくPostgreSQLチューニングKosuke Kida
 
レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)
レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)
レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)NTT DATA Technology & Innovation
 
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)NTT DATA Technology & Innovation
 
メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?Takuya Ueda
 
監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性
監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性
監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性Ohyama Masanori
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Akihiro Suda
 

Was ist angesagt? (20)

分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)分散トレーシング技術について(Open tracingやjaeger)
分散トレーシング技術について(Open tracingやjaeger)
 
統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
統計情報のリセットによるautovacuumへの影響について(第39回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
SQLアンチパターン - 開発者を待ち受ける25の落とし穴 (拡大版)
 
PostgreSQLアンチパターン
PostgreSQLアンチパターンPostgreSQLアンチパターン
PostgreSQLアンチパターン
 
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
AlloyDBを触ってみた!(第33回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
行ロックと「LOG: process 12345 still waiting for ShareLock on transaction 710 afte...
行ロックと「LOG:  process 12345 still waiting for ShareLock on transaction 710 afte...行ロックと「LOG:  process 12345 still waiting for ShareLock on transaction 710 afte...
行ロックと「LOG: process 12345 still waiting for ShareLock on transaction 710 afte...
 
MySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいことMySQL 5.7にやられないためにおぼえておいてほしいこと
MySQL 5.7にやられないためにおぼえておいてほしいこと
 
世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)
世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)
世の中のPostgreSQLエンジニアのpsql設定(第34回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニング雑なMySQLパフォーマンスチューニング
雑なMySQLパフォーマンスチューニング
 
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
pg_hint_planを知る(第37回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
PostgreSQL16新機能紹介 - libpq接続ロード・バランシング(第41回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
PostgreSQLのリカバリ超入門(もしくはWAL、CHECKPOINT、オンラインバックアップの仕組み)
 
PostgreSQL 15の新機能を徹底解説
PostgreSQL 15の新機能を徹底解説PostgreSQL 15の新機能を徹底解説
PostgreSQL 15の新機能を徹底解説
 
Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方Javaのログ出力: 道具と考え方
Javaのログ出力: 道具と考え方
 
まずやっとくPostgreSQLチューニング
まずやっとくPostgreSQLチューニングまずやっとくPostgreSQLチューニング
まずやっとくPostgreSQLチューニング
 
レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)
レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)
レプリケーション遅延の監視について(第40回PostgreSQLアンカンファレンス@オンライン 発表資料)
 
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
PostgreSQLのロール管理とその注意点(Open Source Conference 2022 Online/Osaka 発表資料)
 
メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?メルカリ・ソウゾウでは どうGoを活用しているのか?
メルカリ・ソウゾウでは どうGoを活用しているのか?
 
監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性
監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性
監査要件を有するシステムに対する PostgreSQL 導入の課題と可能性
 
Dockerからcontainerdへの移行
Dockerからcontainerdへの移行Dockerからcontainerdへの移行
Dockerからcontainerdへの移行
 

Ähnlich wie MySQL勉強会 クエリチューニング編

データベースをAI開発に活用
データベースをAI開発に活用データベースをAI開発に活用
データベースをAI開発に活用ReNom User Group
 
Apache Drill で日本語を扱ってみよう + オープンデータ解析
Apache Drill で日本語を扱ってみよう + オープンデータ解析Apache Drill で日本語を扱ってみよう + オープンデータ解析
Apache Drill で日本語を扱ってみよう + オープンデータ解析MapR Technologies Japan
 
PostgreSQL 9.5 の新機能
PostgreSQL 9.5 の新機能PostgreSQL 9.5 の新機能
PostgreSQL 9.5 の新機能Shigetaka Yachi
 
L2 over L3 ecnaspsulations
L2 over L3 ecnaspsulationsL2 over L3 ecnaspsulations
L2 over L3 ecnaspsulationsMotonori Shindo
 

Ähnlich wie MySQL勉強会 クエリチューニング編 (6)

メッチャ役に立つauto_incrementの話
メッチャ役に立つauto_incrementの話メッチャ役に立つauto_incrementの話
メッチャ役に立つauto_incrementの話
 
http2 最速実装 v2
http2 最速実装 v2 http2 最速実装 v2
http2 最速実装 v2
 
データベースをAI開発に活用
データベースをAI開発に活用データベースをAI開発に活用
データベースをAI開発に活用
 
Apache Drill で日本語を扱ってみよう + オープンデータ解析
Apache Drill で日本語を扱ってみよう + オープンデータ解析Apache Drill で日本語を扱ってみよう + オープンデータ解析
Apache Drill で日本語を扱ってみよう + オープンデータ解析
 
PostgreSQL 9.5 の新機能
PostgreSQL 9.5 の新機能PostgreSQL 9.5 の新機能
PostgreSQL 9.5 の新機能
 
L2 over L3 ecnaspsulations
L2 over L3 ecnaspsulationsL2 over L3 ecnaspsulations
L2 over L3 ecnaspsulations
 

Mehr von MicroAd, Inc.(Engineer)

20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用
20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用
20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用MicroAd, Inc.(Engineer)
 
Kafka Connect:Iceberg Sink Connectorを使ってみる
Kafka Connect:Iceberg Sink Connectorを使ってみるKafka Connect:Iceberg Sink Connectorを使ってみる
Kafka Connect:Iceberg Sink Connectorを使ってみるMicroAd, Inc.(Engineer)
 
Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話
Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話
Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話MicroAd, Inc.(Engineer)
 
Chromeの3rd Party Cookie廃止とインターネット広告への影響
Chromeの3rd Party Cookie廃止とインターネット広告への影響Chromeの3rd Party Cookie廃止とインターネット広告への影響
Chromeの3rd Party Cookie廃止とインターネット広告への影響MicroAd, Inc.(Engineer)
 
ベアメタルで実現するSpark&Trino on K8sなデータ基盤
ベアメタルで実現するSpark&Trino on K8sなデータ基盤ベアメタルで実現するSpark&Trino on K8sなデータ基盤
ベアメタルで実現するSpark&Trino on K8sなデータ基盤MicroAd, Inc.(Engineer)
 
DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)
DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)
DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)MicroAd, Inc.(Engineer)
 
InternetWeek2022 - インターネット広告の羅針盤
InternetWeek2022 - インターネット広告の羅針盤InternetWeek2022 - インターネット広告の羅針盤
InternetWeek2022 - インターネット広告の羅針盤MicroAd, Inc.(Engineer)
 
マイクロアドにおけるデータストアの使い分け
マイクロアドにおけるデータストアの使い分けマイクロアドにおけるデータストアの使い分け
マイクロアドにおけるデータストアの使い分けMicroAd, Inc.(Engineer)
 
データセンターネットワークの構成について
データセンターネットワークの構成についてデータセンターネットワークの構成について
データセンターネットワークの構成についてMicroAd, Inc.(Engineer)
 
インフラ領域の技術スタックや業務内容について紹介
インフラ領域の技術スタックや業務内容について紹介インフラ領域の技術スタックや業務内容について紹介
インフラ領域の技術スタックや業務内容について紹介MicroAd, Inc.(Engineer)
 
RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例MicroAd, Inc.(Engineer)
 
アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜
アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜
アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜MicroAd, Inc.(Engineer)
 
アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜MicroAd, Inc.(Engineer)
 
アドテクに機械学習を組み込むための推論の高速化
アドテクに機械学習を組み込むための推論の高速化アドテクに機械学習を組み込むための推論の高速化
アドテクに機械学習を組み込むための推論の高速化MicroAd, Inc.(Engineer)
 
マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜
マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜
マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜MicroAd, Inc.(Engineer)
 
アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜MicroAd, Inc.(Engineer)
 
RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例MicroAd, Inc.(Engineer)
 
社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -
社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -
社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -MicroAd, Inc.(Engineer)
 
Digdagを用いた大規模広告配信ログデータの加工と運用
Digdagを用いた大規模広告配信ログデータの加工と運用Digdagを用いた大規模広告配信ログデータの加工と運用
Digdagを用いた大規模広告配信ログデータの加工と運用MicroAd, Inc.(Engineer)
 
これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~
これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~
これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~MicroAd, Inc.(Engineer)
 

Mehr von MicroAd, Inc.(Engineer) (20)

20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用
20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用
20240229 DEIM2024 【技術報告】広告配信における安定して拡張性のある大量データ処理基盤の必要性と活用
 
Kafka Connect:Iceberg Sink Connectorを使ってみる
Kafka Connect:Iceberg Sink Connectorを使ってみるKafka Connect:Iceberg Sink Connectorを使ってみる
Kafka Connect:Iceberg Sink Connectorを使ってみる
 
Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話
Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話
Apache Kafkaでの大量データ処理がKubernetesで簡単にできて嬉しかった話
 
Chromeの3rd Party Cookie廃止とインターネット広告への影響
Chromeの3rd Party Cookie廃止とインターネット広告への影響Chromeの3rd Party Cookie廃止とインターネット広告への影響
Chromeの3rd Party Cookie廃止とインターネット広告への影響
 
ベアメタルで実現するSpark&Trino on K8sなデータ基盤
ベアメタルで実現するSpark&Trino on K8sなデータ基盤ベアメタルで実現するSpark&Trino on K8sなデータ基盤
ベアメタルで実現するSpark&Trino on K8sなデータ基盤
 
DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)
DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)
DDD&Scalaで作られたプロダクトはその後どうなったか?(Current state of products made with DDD & Scala)
 
InternetWeek2022 - インターネット広告の羅針盤
InternetWeek2022 - インターネット広告の羅針盤InternetWeek2022 - インターネット広告の羅針盤
InternetWeek2022 - インターネット広告の羅針盤
 
マイクロアドにおけるデータストアの使い分け
マイクロアドにおけるデータストアの使い分けマイクロアドにおけるデータストアの使い分け
マイクロアドにおけるデータストアの使い分け
 
データセンターネットワークの構成について
データセンターネットワークの構成についてデータセンターネットワークの構成について
データセンターネットワークの構成について
 
インフラ領域の技術スタックや業務内容について紹介
インフラ領域の技術スタックや業務内容について紹介インフラ領域の技術スタックや業務内容について紹介
インフラ領域の技術スタックや業務内容について紹介
 
RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例
 
アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜
アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜
アドテクを支える基盤 〜10Tバイト/日のビッグデータを処理する〜
 
アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜
 
アドテクに機械学習を組み込むための推論の高速化
アドテクに機械学習を組み込むための推論の高速化アドテクに機械学習を組み込むための推論の高速化
アドテクに機械学習を組み込むための推論の高速化
 
マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜
マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜
マイクロアドのデータ基盤について アドテクを支える基盤〜10Tバイト/日のビッグデータを処理する〜
 
アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜アドテクを支える技術 〜1日40億リクエストを捌くには〜
アドテクを支える技術 〜1日40億リクエストを捌くには〜
 
RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例RTBにおける機械学習の活用事例
RTBにおける機械学習の活用事例
 
社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -
社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -
社内問い合わせ&申請・承認業務の 管理方法 - Jira Service Management 事例紹介 -
 
Digdagを用いた大規模広告配信ログデータの加工と運用
Digdagを用いた大規模広告配信ログデータの加工と運用Digdagを用いた大規模広告配信ログデータの加工と運用
Digdagを用いた大規模広告配信ログデータの加工と運用
 
これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~
これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~
これから機械学習エンジニアとして戦っていくみなさんへ ~MLOps というマインドセットについて~
 

Kürzlich hochgeladen

論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A surveyToru Tamaki
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Yuma Ohgami
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)Hiroki Ichikura
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...Toru Tamaki
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略Ryo Sasaki
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNetToru Tamaki
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムsugiuralab
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdftaisei2219
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものですiPride Co., Ltd.
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Danieldanielhu54
 

Kürzlich hochgeladen (10)

論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey論文紹介:Semantic segmentation using Vision Transformers: A survey
論文紹介:Semantic segmentation using Vision Transformers: A survey
 
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
Open Source UN-Conference 2024 Kawagoe - 独自OS「DaisyOS GB」の紹介
 
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
【早稲田AI研究会 講義資料】3DスキャンとTextTo3Dのツールを知ろう!(Vol.1)
 
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
論文紹介:Content-Aware Token Sharing for Efficient Semantic Segmentation With Vis...
 
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
[DevOpsDays Tokyo 2024] 〜デジタルとアナログのはざまに〜 スマートビルディング爆速開発を支える 自動化テスト戦略
 
論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet論文紹介:Automated Classification of Model Errors on ImageNet
論文紹介:Automated Classification of Model Errors on ImageNet
 
スマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システムスマートフォンを用いた新生児あやし動作の教示システム
スマートフォンを用いた新生児あやし動作の教示システム
 
TSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdfTSAL operation mechanism and circuit diagram.pdf
TSAL operation mechanism and circuit diagram.pdf
 
SOPを理解する 2024/04/19 の勉強会で発表されたものです
SOPを理解する       2024/04/19 の勉強会で発表されたものですSOPを理解する       2024/04/19 の勉強会で発表されたものです
SOPを理解する 2024/04/19 の勉強会で発表されたものです
 
Postman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By DanielPostman LT Fukuoka_Quick Prototype_By Daniel
Postman LT Fukuoka_Quick Prototype_By Daniel
 

MySQL勉強会 クエリチューニング編

  • 3.
  • 5. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 6. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 7. 1章 対話的にクエリを作る City:都市テーブル +-------------+------------+----------+------+-----+ | ColumnID | ColumnName | Type | Null | Key | +-------------+------------+----------+------+-----+ | ID | 都市ID | int(11) | NO | PRI | | Name | 都市名 | char(35) | NO | | | CountryCode | 国コード | char(3) | NO | MUL | | District | 地区 | char(20) | NO | | | Population | 都市人口 | int(11) | NO | MUL | +-------------+------------+----------+------+-----+ +----------------+------------------+---------------------------------------------------------------------------------------+------+-----+ | ColumnID | ColumnName | Type | Null | Key | +----------------+------------------+---------------------------------------------------------------------------------------+------+-----+ | Code | 国コード | char(3) | NO | PRI | | Name | 国名 | char(52) | NO | | | Continent | 大陸 | enum('Asia','Europe','North America','Africa','Oceania','Antarctica','South America') | NO | | | Region | 地帯 | char(26) | NO | | | SurfaceArea | 国土面積 | float(10,2) | NO | | | IndepYear | 独立年 | smallint(6) | YES | | | Population | 国人口 | int(11) | NO | | | LifeExpectancy | 平均寿命 | float(3,1) | YES | | | GNP | 国民総生産 | float(10,2) | YES | | | GNPOld | 国民総生産(過去) | float(10,2) | YES | | | LocalName | 国名(ローカル) | char(45) | NO | | | GovernmentForm | 政治体系 | char(45) | NO | | | HeadOfState | 国家元首 | char(60) | YES | | | Capital | 首都コード | int(11) | YES | | | Code2 | 国コード(略) | char(2) | NO | | +----------------+------------------+---------------------------------------------------------------------------------------+------+-----+ Country:国テーブル 件数:4079 件数:239 当勉強会ではMySQLのサンプルデータベース内のテーブルを使用し、 実際にクエリを組んで見解を広げて頂きます。 Code ・ ・ Country ・ CountryCode ・ City
  • 8. Population / 2 +------------+ | Population | +------------+ | 4848150 | | 3990115 | | 4990810 | +------------+ 1章 対話的にクエリを作る 抽出項目 都市名 国コード 都市人口 都市人口の半数が、 瀋陽の人口よりも多い都市 抽出条件 クエリ SELECT Cty1.Name, Cty1.CountryCode, Cty1.Population FROM City Cty1 WHERE Cty.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.Name = 'Shenyang' ); City(都市テーブル) +-------------+------------+----------+-----+ | ColumnID | ColumnName | Type | Key | +-------------+------------+----------+-----+ | ID | 都市ID | int(11) | PRI | | Name | 都市名 | char(35) | | | CountryCode | 国コード | char(3) | MUL | | District | 地区 | char(20) | | | Population | 都市人口 | int(11) | MUL | +-------------+------------+----------+-----+ テーブル 抽出イメージ Cty1(City) +------+----------+-------------+----------+------------+ | ID | Name | CountryCode | District | Population | +------+----------+-------------+----------+------------+ | 1890 | Shanghai | CHN | Shanghai | 9696300 | | 1532 | Tokyo | JPN | Tokyo-to | 7980230 | | 2331 | Seoul | KOR | Seoul | 9981620 | +------+----------+-------------+----------+------------+ 瀋陽の人口 +------------+ | Population | +------------+ | 4265200 | +------------+ Cty1(City) +------+----------+-------------+----------+------------+ | ID | Name | CountryCode | District | Population | +------+----------+-------------+----------+------------+ | 1890 | Shanghai | CHN | Shanghai | 9696300 |○ | 1532 | Tokyo | JPN | Tokyo-to | 7980230 | | 2331 | Seoul | KOR | Seoul | 9981620 |○ +------+----------+-------------+----------+------------+ Cty1(City) +------+----------+-------------+----------+------------+ | ID | Name | CountryCode | District | Population | +------+----------+-------------+----------+------------+ | 1890 | Shanghai | CHN | Shanghai | 9696300 |○ | 1532 | Tokyo | JPN | Tokyo-to | 7980230 | | 2331 | Seoul | KOR | Seoul | 9981620 |○ +------+----------+-------------+----------+------------+ Population / 2 +------------+ | Population | +------------+ | 4848150 | | 3990115 | | 4990810 | +------------+
  • 9. 1章 対話的にクエリを作る 完? +----------+-------------+------------+ | Name | CountryCode | Population | +----------+-------------+------------+ | Shanghai | CHN | 9696300 | | Seoul | KOR | 9981620 | +----------+-------------+------------+ 実 行 結 果
  • 11. 1章 対話的にクエリを作る mysql> SELECT … WHERE Cty2.Name = 'Shenyang'); ・ ・ ・ 8 rows in set (0.00 sec) 速いッ!
  • 14. 1章 対話的にクエリを作る 先程作成したクエリの実行計画を確認してみましょう。 +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ EXPLAIN SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.Name = 'Shenyang' ); クエリ 実行計画 +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ INDEXが使われてない!テーブルスキャン!! 外部クエリ サブクエリ
  • 16. 1章 対話的にクエリを作る 例えばこんなクエリ。 SELECT * FROM City WHERE Name = 'Tokyo'; City(都市テーブル) 件数:4079 +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ row75 row1 row1001 row561 row314 row245 row843 row48 row1831 row181row468 row188 row2188 row821 row87 row987 row456 row6 row236 row4000 row813 row3 row30 row209 row131 row2430 row2120 row21 row2901 row333 row713 row3557 row1684 row338 row3388 row1088 row10 row1540 row3140row1059 row193 row412 row198 row15 row681 row1926 row1985 row2792 row961 row461 row1563 row3154 row1863 row731 row462 row1462 row3311 row1991 row1535 row501 row852 row3841 row100 row1091 row491 row481 row584 row522 row521 row64 row487 row983 row1616 row3731 City row737 row1379 row3838 row1103 row588 row519 row819 row4009 row12 Cityの行を一つ一つを確認して、Nameが'Tokyo'の行を探してください。
  • 19. 1章 対話的にクエリを作る SELECT * FROM City WHERE Name = 'Tokyo'; City(都市テーブル) 件数:4079 +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | MUL | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ row1863 City NameカラムのINDEX情報 'Tokyo' A - K L - Z A - D E - G H - I L - O P - R S - Z Peking Pusan Qazvin Rotterdam Roma London Liverpool Mexico New York Okinawa Sydney Tokyo Washington Valera Zelenograd … … … A - K L - Z L - O P - R S - Z Sydney Tokyo Washington Valera Zelenograd
  • 21. +-------------+------------+----------+------+-----+ | ColumnID | ColumnName | Type | Null | Key | +-------------+------------+----------+------+-----+ | ID | 都市ID | int(11) | NO | PRI | | Name | 都市名 | char(35) | NO | | | CountryCode | 国コード | char(3) | NO | MUL | | District | 地区 | char(20) | NO | | | Population | 都市人口 | int(11) | NO | MUL | +-------------+------------+----------+------+-----+ 1章 対話的にクエリを作る MySQLには是非INDEXを使って頂きたい。 サブクエリからチューニングしてみます。 都市人口の半分が瀋陽の人口よりも多い都市 抽出仕様 City:都市テーブル +-------------+------------+----------+------+-----+ | ColumnID | ColumnName | Type | Null | Key | +-------------+------------+----------+------+-----+ | ID | 都市ID | int(11) | NO | PRI | | Name | 都市名 | char(35) | NO | | | CountryCode | 国コード | char(3) | NO | MUL | | District | 地区 | char(20) | NO | | | Population | 都市人口 | int(11) | NO | MUL | +-------------+------------+----------+------+-----+ サブクエリ SELECT Cty1.Name, Cty1.CountryCode, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.Name = 'Shenyang' ); 都市人口の半分が中国の瀋陽の人口よりも多い都市 瀋陽が中国の都市であることは明確であり、 抽出条件に国コードが追加されても問題はない。 SELECT Cty1.Name, Cty1.CountryCode, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE AND Cty2.Name = 'Shenyang' ); SELECT Cty1.Name, Cty1.CountryCode, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' );
  • 22. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 1章 対話的にクエリを作る 修正後の実行計画は… +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ); クエリ チューニング前の実行計画 サブクエリの検索条件にCountryCodeを指定した ことで、INDEXを利用した検索が可能に! チューニング後の実行計画
  • 23. 1章 対話的にクエリを作る 次は外部クエリ。 +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ City:都市テーブル +-------------+------------+----------+------+-----+ | ColumnID | ColumnName | Type | Null | Key | +-------------+------------+----------+------+-----+ | ID | 都市ID | int(11) | NO | PRI | | Name | 都市名 | char(35) | NO | | | CountryCode | 国コード | char(3) | NO | MUL | | District | 地区 | char(20) | NO | | | Population | 都市人口 | int(11) | NO | MUL | +-------------+------------+----------+------+-----+ クエリ 実行計画 SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ); あれ?! INDEXは?! SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ); +-------------+------------+----------+------+-----+ | ColumnID | ColumnName | Type | Null | Key | +-------------+------------+----------+------+-----+ | ID | 都市ID | int(11) | NO | PRI | | Name | 都市名 | char(35) | NO | | | CountryCode | 国コード | char(3) | NO | MUL | | District | 地区 | char(20) | NO | | | Population | 都市人口 | int(11) | NO | MUL | +-------------+------------+----------+------+-----+ +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+
  • 24. 1章 対話的にクエリを作る WHERE句内をよく見てください。 クエリ SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ); SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ); 索引列に対して演算処理を行っている場合、 オプティマイザはINDEXを使用することが出来ないのです。
  • 25. 1章 対話的にクエリを作る ではどうするか。 都市人口の半分が中国瀋陽の人口よりも多い都市 抽出仕様 SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population / 2 > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ); SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ) * 2; = 都市人口が中国瀋陽の倍の人口よりも多い都市 抽出の仕様に影響なし クエリ
  • 26. +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | const | 363 | Using where | +----+-------------+-------+------+---------------+-------------+---------+-------+------+-------------+ 1章 対話的にクエリを作る 修正後の実行計画は… +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+ | 1 | PRIMARY | Cty1 | range | Population | Population | 4 | NULL | 8 | Using where | | 2 | SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | | 363 | Using where | +----+-------------+-------+-------+---------------+-------------+---------+------+------+-------------+ SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population > ( SELECT Cty2.Population FROM City Cty2 WHERE Cty2.CountryCode = 'CHN' AND Cty2.Name = 'Shenyang' ) * 2; クエリ クエリチューニング前実行計画 索引列の演算処理を、右辺に移すことで INDEXを利用した範囲検索が可能に! クエリチューニング後実行計画
  • 27. 1章 対話的にクエリを作る 仕上げの実行結果確認 +----------+-------------+------------+ | Name | CountryCode | Population | +----------+-------------+------------+ | Shanghai | CHN | 9696300 | | Seoul | KOR | 9981620 | +----------+-------------+------------+ 実 行 結 果
  • 29. 1章 対話的にクエリを作る 索引列を指定しても、オプティマイザがINDEXを 使用できないパターンは他にも存在します。 WHERE Index_Column IS NULL NULL述語を使用 WHERE SUBSTRING(Index_Column, 1, 3) = 'abc' SQL関数を使用 WHERE Index_Column <> 'abc' 否定形での条件指定 WHERE Index_Column = 'abc' OR Index_Column = 'def' ORでの条件指定(INへの置き換えで対応可) WHERE Index_Column LIKE '%abc%' 中間一致、後方一致でのLIKE述語を使用(前方一致は使用可能) ・ ・ ・
  • 31. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 32. 2章 オプティマイザの判断 人口が400000人超えの都市 都市名 都市人口 SELECT Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000; 抽出条件 抽出項目 クエリテーブル City(都市テーブル) +-------------+------------+----------+-----+ | ColumnID | ColumnName | Type | Key | +-------------+------------+----------+-----+ | ID | 都市ID | int(11) | PRI | | Name | 都市名 | char(35) | | | CountryCode | 国コード | char(3) | MUL | | District | 地区 | char(20) | | | Population | 都市人口 | int(11) | MUL | +-------------+------------+----------+-----+ 抽出イメージ Cty +------+------------+-------------+----------------+------------+ | ID | Name | CountryCode | District | Population | +------+------------+-------------+----------------+------------+ | 135 | Canberra | AUS | Capital Region | 322723 | | 1570 | Gifu | JPN | Gifu | 408007 | | 1822 | Ottawa | CAN | Ontario | 335277 | | 2318 | Pyongyang | PRK | Pyongyang-si | 2484000 | | 3209 | Bratislava | SVK | Bratislava | 448292 | | 3831 | Atlanta | USA | Georgia | 416474 | +------+------------+-------------+----------------+------------+ Cty +------+------------+-------------+----------------+------------+ | ID | Name | CountryCode | District | Population | +------+------------+-------------+----------------+------------+ | 135 | Canberra | AUS | Capital Region | 322723 | | 1570 | Gifu | JPN | Gifu | 408007 |○ | 1822 | Ottawa | CAN | Ontario | 335277 | | 2318 | Pyongyang | PRK | Pyongyang-si | 2484000 |○ | 3209 | Bratislava | SVK | Bratislava | 448292 |○ | 3831 | Atlanta | USA | Georgia | 416474 |○ +------+------------+-------------+----------------+------------+ Cty +------+------------+-------------+----------------+------------+ | ID | Name | CountryCode | District | Population | +------+------------+-------------+----------------+------------+ | 135 | Canberra | AUS | Capital Region | 322723 | | 1570 | Gifu | JPN | Gifu | 408007 |○ | 1822 | Ottawa | CAN | Ontario | 335277 | | 2318 | Pyongyang | PRK | Pyongyang-si | 2484000 |○ | 3209 | Bratislava | SVK | Bratislava | 448292 |○ | 3831 | Atlanta | USA | Georgia | 416474 |○ +------+------------+-------------+----------------+------------+
  • 34. 2章 オプティマイザの判断 +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ EXPLAIN SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000; …あれっ!? 実行計画 実行計画は…
  • 35. +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ 2章 オプティマイザの判断 possible_keysを見てください。 INDEX「Population」は使える状況であることがわかります。 +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | SIMPLE | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | | 2 | SUBQUERY | Cty2 | ALL | NULL | NULL | NULL | NULL | 4051 | Using where | +----+-------------+-------+------+---------------+------+---------+------+------+-------------+ ※1章のチューニング前の実行計画
  • 38. 2章 オプティマイザの判断 試しに人口600000人超え(表全体の約10%)の都市を抽出してみます。 +----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+ | 1 | SIMPLE | Cty | range | Population | Population | 4 | NULL | 428 | Using where | +----+-------------+-------+-------+---------------+------------+---------+------+------+-------------+ EXPLAIN SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 600000; この条件の場合は、INDEXを利用した方が効率が良いと判断したようです。 実行計画
  • 40. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 41. 3章 サブクエリは「データ」の集合 SELECT Ctr.Name CountryName, Sub.Name CityName, Sub.Population FROM Country Ctr LEFT JOIN ( SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000 ) Sub ON Ctr.Code = Sub.CountryCode; City(都市テーブル) +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ Country(国テーブル) +----------+---------------+-----+ | ColumnID | ColumnName | Key | +----------+---------------+-----+ | Code | 国コード | PRI | | Name | 国名 | | ==============省略================ 全ての国名の一覧を表示。 各国に人口が400000人以上の都市が存在する場合、 その各都市の名称と人口の情報を付与する。 存在しない場合はNULLを表示する。 国名 都市名 都市人口 抽出条件 抽出項目 クエリテーブル 抽出イメージ Ctr +------+---------------+ | Code | Name | +------+---------------+ | JPN | Japan | | KOR | South Korea | | SVK | Slovakia | | USA | United States | +------+---------------+ Cty +------------+-------------+------------+ | Name | CountryCode | Population | +------------+-------------+------------+ | Gifu | JPN | 408007 | | Pyongyang | PRK | 2484000 | | Bratislava | SVK | 448292 | | Atlanta | USA | 416474 | +------------+-------------+------------+ Ctr LEFT JOIN Sub +---------------+------------+------------+ | CountryName | CityName | Population | +---------------+------------+------------+ | Japan | Gifu | 408007 | | South Korea | NULL | NULL | | Slovakia | Bratislava | 448292 | | United States | Atlanta | 416474 | +---------------+------------+------------+ Sub +------------+-------------+------------+ | Name | CountryCode | Population | +------------+-------------+------------+ | Gifu | JPN | 408007 |○ | Pyongyang | PRK | 2484000 | | Bratislava | SVK | 448292 |○ | Atlanta | USA | 416474 |○ +------------+-------------+------------+ + =
  • 42. 3章 サブクエリは「データ」の集合 クエリの実行計画を確認してみます。 +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | | | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | | | 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ EXPLAIN SELECT Ctr.Name CountryName, Sub.Name CityName, Sub.Population FROM Country Ctr LEFT JOIN ( SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000 ) Sub ON Ctr.Code = Sub.CountryCode; +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | | | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | | | 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ 結合キーとして、 INDEXが使われていません。 実行計画
  • 43. derived2 3章 サブクエリは「データ」の集合 図解するとこんな感じです。 +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | | | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | | | 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ Cty PK INDEX Ctr サブクエリにて抽出した集合には PKやINDEXの情報は含まれない。 Ctrを基準にderived2とJOIN PK INDEX ※基準になるテーブルのINDEXは使われません。
  • 45. 3章 サブクエリは「データ」の集合 SELECT Ctr.Name CountryName, Sub.Name CityName, Sub.Population FROM Country Ctr LEFT JOIN ( SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000 ) Sub ON Ctr.Code = Sub.CountryCode; City(都市テーブル) +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ Country(国テーブル) +----------+---------------+-----+ | ColumnID | ColumnName | Key | +----------+---------------+-----+ | Code | 国コード | PRI | | Name | 国名 | | ==============省略================ クエリテーブル 抽出イメージ Ctr +------+---------------+ | Code | Name | +------+---------------+ | JPN | Japan | | KOR | South Korea | | SVK | Slovakia | | USA | United States | +------+---------------+ Cty +------------+-------------+------------+ | Name | CountryCode | Population | +------------+-------------+------------+ | Gifu | JPN | 408007 | | Pyongyang | PRK | 2484000 | | Bratislava | SVK | 448292 | | Atlanta | USA | 416474 | +------------+-------------+------------+ Ctr LEFT JOIN Sub +---------------+------------+------------+ | CountryName | CityName | Population | +---------------+------------+------------+ | Japan | Gifu | 408007 | | South Korea | NULL | NULL | | Slovakia | Bratislava | 448292 | | United States | Atlanta | 416474 | +---------------+------------+------------+ Sub +------------+-------------+------------+ | Name | CountryCode | Population | +------------+-------------+------------+ | Gifu | JPN | 408007 |○ | Pyongyang | PRK | 2484000 | | Bratislava | SVK | 448292 |○ | Atlanta | USA | 416474 |○ +------------+-------------+------------+ + = Countryテーブルと結合するのはCityテーブルではなく、 あくまでもSubというデータの集合(テンポラリテーブル)
  • 46. 3章 サブクエリは「データ」の集合 ではどうするか。 SELECT Ctr.Name CountryName, Sub.Name CityName, Sub.Population FROM Country Ctr LEFT JOIN (SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000 ) Sub ON Ctr.Code = Sub.CountryCode; SELECT Ctr.Name CountryName, Cty.Name CityName, Cty.Population FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode; クエリ SELECT Ctr.Name CountryName, Cty.Name CityName, Cty.Population FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode AND Cty.Population > 400000; Ctr +------+---------------+ | Code | Name | +------+---------------+ | JPN | Japan | | KOR | South Korea | | SVK | Slovakia | | USA | United States | +------+---------------+ Cty +------------+-------------+------------+ | Name | CountryCode | Population | +------------+-------------+------------+ | Gifu | JPN | 408007 | | Kwangmyong | KOR | 350914 | | Pyongyang | PRK | 2484000 | | Bratislava | SVK | 448292 | | Atlanta | USA | 416474 | +------------+-------------+------------+ Ctr LEFT JOIN Cty +---------------+------------+------------+ | CountryName | CityName | Population | +---------------+------------+------------+ | Japan | Gifu | 408007 | | South Korea | Kwangmyong | 350914 | | Slovakia | Bratislava | 448292 | | United States | Atlanta | 416474 | +---------------+------------+------------+ + = 抽出イメージ City(都市テーブル) +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ Country(国テーブル) +----------+---------------+-----+ | ColumnID | ColumnName | Key | +----------+---------------+-----+ | Code | 国コード | PRI | | Name | 国名 | | ==============省略================ テーブル Cty +------------+-------------+------------+ | Name | CountryCode | Population | +------------+-------------+------------+ | Gifu | JPN | 408007 | | Kwangmyong | KOR | 350914 | | Pyongyang | PRK | 2484000 | | Bratislava | SVK | 448292 | | Atlanta | USA | 416474 | +------------+-------------+------------+ Ctr LEFT JOIN Cty +---------------+------------+------------+ | CountryName | CityName | Population | +---------------+------------+------------+ | Japan | Gifu | 408007 | | South Korea | NULL | NULL | | Slovakia | Bratislava | 448292 | | United States | Atlanta | 416474 | +---------------+------------+------------+
  • 47. +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | | | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | | | 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ 3章 サブクエリは「データ」の集合 修正後の実行計画は… +----+-------------+-------+------+------------------------+-------------+---------+----------------+------+-------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+------------------------+-------------+---------+----------------+------+-------+ | 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | | | 1 | SIMPLE | Cty | ref | CountryCode,Population | CountryCode | 3 | world.Ctr.Code | 7 | | +----+-------------+-------+------+------------------------+-------------+---------+----------------+------+-------+ EXPLAIN SELECT Ctr.Name CountryName, Cty.Name CityName, Cty.Population FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode AND Cty.Population > 400000; クエリ サブクエリを使わず直接テーブル同士をJOINしたことで、 INDEXを利用したJOINが可能に! クエリチューニング前実行計画クエリチューニング後実行計画
  • 49. 3章 サブクエリは「データ」の集合 チューニング前のクエリの結合方式を内部結合にすると… +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ | 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 241 | | | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | | | 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+------------+------+---------------+------+---------+------+------+-------------+ EXPLAIN SELECT Ctr.Name CountryName, Sub.Name CityName, Sub.Population FROM Country Ctr LEFT JOIN ( SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000 ) Sub ON Ctr.Code = Sub.CountryCode; EXPLAIN SELECT Ctr.Name CountryName, Sub.Name CityName, Sub.Population FROM Country Ctr INNER JOIN ( SELECT Cty.CountryCode, Cty.Name, Cty.Population FROM City Cty WHERE Cty.Population > 400000 ) Sub ON Ctr.Code = Sub.CountryCode; +----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | | | 1 | PRIMARY | Ctr | eq_ref | PRIMARY | PRIMARY | 3 | Sub.CountryCode | 1 | | | 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+ INDEXが… 使われている!? 実行計画
  • 50. 3章 サブクエリは「データ」の集合 図で説明します +----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 737 | | | 1 | PRIMARY | Ctr | eq_ref | PRIMARY | PRIMARY | 3 | Sub.CountryCode | 1 | | | 2 | DERIVED | Cty | ALL | Population | NULL | NULL | NULL | 4051 | Using where | +----+-------------+------------+--------+---------------+---------+---------+-----------------+------+-------------+ Cty PK INDEX derived2 Ctr derived2を基準にCtrとJOIN 内部結合の場合、どちらを基準にしても良いため、 オプティマイザが効率的と判断した集合を基準に結合する。 サブクエリにて抽出した集合には PKやINDEXの情報は含まれていない。 PK PK INDEX
  • 52. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 53. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 54. 4章 ソートとインデックス 全ての国名とその国が所有する都市数 クエリ SELECT Ctr.Code CountryCode, Ctr.Name CountryName, COUNT(Cty.ID) CityCount FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode GROUP BY Ctr.Code, Ctr.Name; 抽出仕様 抽出項目 国コード 国名 都市数 City(都市テーブル) +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ Country(国テーブル) +----------+---------------+-----+ | ColumnID | ColumnName | Key | +----------+---------------+-----+ | Code | 国コード | PRI | | Name | 国名 | | ==============省略================ テーブル 抽出イメージ Ctr +------+---------------+ | Code | Name | +------+---------------+ | ATA | Antarctica | | JPN | Japan | | KOR | South Korea | | USA | United States | +------+---------------+ Cty +------+----------+-------------+ | ID | Name | CountryCode | +------+----------+-------------+ | 129 | Aruba | ABW | | 1532 | Tokyo | JPN | | 1534 | Osaka | JPN | | 2331 | Seoul | KOR | | 3793 | New York | USA | +------+----------+-------------+ Ctr LEFT JOIN Cty +------+---------------+------+----------+-------------+ | Code | Name | ID | Name | CountryCode | +------+---------------+------+----------+-------------+ | ATA | Antarctica | NULL | NULL | NULL | | JPN | Japan | 1532 | Tokyo | JPN | | JPN | Japan | 1534 | Osaka | JPN | | KOR | South Korea | 2331 | Seoul | KOR | | USA | United States | 3793 | New York | USA | +------+---------------+------+----------+-------------+ + = Ctr LEFT JOIN Cty GROUP BY Ctr.Column +-------------+---------------+-----------+ | CountryCode | CountryName | CityCount | +-------------+---------------+-----------+ | ATA | Antarctica | 0 | | JPN | Japan | 2 | | KOR | South Korea | 1 | | USA | United States | 1 | +-------------+---------------+-----------+ Cty +------+----------+-------------+ | ID | Name | CountryCode | +------+----------+-------------+ | 129 | Aruba | ABW | | 1532 | Tokyo | JPN |○ | 1534 | Osaka | JPN |○ | 2331 | Seoul | KOR |○ | 3793 | New York | USA |○ +------+----------+-------------+
  • 55. 4章 ソートとインデックス SELECT Ctr.Code CountryCode, Ctr.Name CountryName, COUNT(Cty.ID) CityCount FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode GROUP BY Ctr.Code, Ctr.Name; +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort | | 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ テーブルの結合キーに関してはINDEXが使われていますが、 今回注目して頂きたいのは結合基準となるテーブルのExtraフィールドです。 クエリの実行計画を確認してみます。 実行計画 +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort | | 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort | | 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+
  • 56. 4章 ソートとインデックス 図解するとこんな感じ。 Ctr Ctr1 Ctr2 Ctr3 Ctr4 Cty Cty1-1 Cty3-1 Cty2-2 Cty2-1 Cty4-1 テンポラリテーブル LEFT JOIN SORT 出力 Ctr1 Ctr2 Ctr3 Ctr4 Cty2-1 Cty2-2 Cty3-1 Cty4-1 Ctr1 Ctr2 Ctr3 Ctr4 Cty3-1 Cty2-2 Cty2-1 Cty4-1 Ctr +------+---------------+ | Code | Name | +------+---------------+ | USA | United States |4 | JPN | Japan |2 | ATA | Antarctica |1 | KOR | South Korea |3 +------+---------------+ Cty +----------+-------------+ | Name | CountryCode | +----------+-------------+ | Osaka | JPN |2-2 | Seoul | KOR |3-1 | Aruba | ABW |1-1 | New York | USA |4-1 | Tokyo | JPN |2-1 +----------+-------------+ Ctr LEFT JOIN Cty GROUP BY Ctr.Columns +-------------+---------------+-----------+ | CountryCode | CountryName | CityCount | +-------------+---------------+-----------+ | ATA | Antarctica | 0 | | JPN | Japan | 2 | | KOR | South Korea | 1 | | USA | United States | 1 | +-------------+---------------+-----------+ テ ン ポ ラ リ テ ー ブ ル Using temporary Using filesort
  • 57. 4章 ソートとインデックス Ctr Ctr1 Ctr2 Ctr3 Ctr4 Cty Cty1-1 Cty3-1 Cty2-2 Cty2-1 Cty4-1 テンポラリテーブル LEFT JOIN SORT 出力 Ctr1 Ctr2 Ctr3 Ctr4 Cty2-1 Cty2-2 Cty3-1 Cty4-1 Ctr1 Ctr2 Ctr3 Ctr4 Cty3-1 Cty2-2 Cty2-1 Cty4-1 Ctr +------+---------------+ | Code | Name | +------+---------------+ | USA | United States |4 | JPN | Japan |2 | ATA | Antarctica |1 | KOR | South Korea |3 +------+---------------+ Cty +----------+-------------+ | Name | CountryCode | +----------+-------------+ | Tokyo | JPN |2-2 | Seoul | KOR |3-1 | Aruba | ABW |1-1 | New York | USA |4-1 | Osaka | JPN |2-1 +----------+-------------+ Ctr LEFT JOIN Cty GROUP BY Ctr_Column +-------------+---------------+-----------+ | CountryCode | CountryName | CityCount | +-------------+---------------+-----------+ | ATA | Antarctica | 0 | | JPN | Japan | 2 | | KOR | South Korea | 1 | | USA | United States | 1 | +-------------+---------------+-----------+ テ ン ポ ラ リ テ ー ブ ル Using temporary Using filesort 実はこいつら、やっつけられます。
  • 58. 4章 ソートとインデックス 対応方法の一つとして複合INDEXを用いる方法があります。 SELECT Ctr.Code CountryCode, Ctr.Name CountryName, COUNT(Cty.ID) CityCount FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode GROUP BY Ctr.Code, Ctr.Name; 上記クエリのGROUP BY句にて使用する集計キーに対して、 下記のコマンドで複合INDEXを貼ります。 ALTER TABLE Country ADD INDEX mul_idx1(Code, Name);
  • 59. 4章 ソートとインデックス 複合INDEX対応後のクエリの実行計画を確認してみます。 SELECT Ctr.Code CountryCode, Ctr.Name CountryName, COUNT(Cty.ID) CityCount FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode GROUP BY Ctr.Code, Ctr.Name; +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ | 1 | SIMPLE | Ctr | index | NULL | mul_idx1 | 55 | NULL | 1 | Using index | | 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index | +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ +---------+----------+--------------+-------------+ | Table | Key_name | Seq_in_index | Column_name | +---------+----------+--------------+-------------+ | Country | PRIMARY | 1 | Code | | Country | mul_idx1 | 1 | Code | | Country | mul_idx1 | 2 | Name | +---------+----------+--------------+-------------+ 実行計画 複合INDEXを貼ることによって、 INDEXを用いたソートが可能に!
  • 61. 4章 ソートとインデックス mul_idx1(Code, Name)のINDEX情報 head AAA CCC 333 333 BBB 222 222111 111 Code Name ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ 複合INDEXは下記図のようなINDEX情報となります。 INDEXとして保持している情報はCode、Nameの順にソートされています。 つまりINDEX順に行を取り出したその時、既にソートは終わっているのです。
  • 64. 4章 ソートとインデックス CodeのみのINDEX情報 head AAA CCCBBBCode ① 単一INDEXは下記図のようなINDEX情報となります。 ② ③ 上の図だけでダメなのはわかりますね。 インデックス順にデータを取得しても、Name列はソートされていない状態です。
  • 66. 4章 ソートとインデックス mul_idx1(Name, Code)のINDEX情報 head 1 3 CCDCCC CCE 2 BBCBBB BBDAABAAA AAC Name Code ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ 複合INDEXの定義順を逆にしてみます。 SELECT Ctr.Code CountryCode, Ctr.Name CountryName, COUNT(Cty.ID) CityCount FROM Country Ctr LEFT JOIN City Cty ON Ctr.Code = Cty.CountryCode GROUP BY Ctr.Code, Ctr.Name; クエリ INDEX情報はName、Codeの順でソートされています。 よって、INDEX順でデータを取得したとしても、 Code、Name順にソートする必要が出てきます。
  • 70. 4章 まとめ GROUP BY、ORDER BYでも インデックスの利用を意識すること!
  • 71. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 72. 5章 インデックスは万能ではない 4章で例に挙げたクエリの実際の実行時間は以下です。 +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ | 1 | SIMPLE | Ctr | ALL | NULL | NULL | NULL | NULL | 205 | Using temporary; Using filesort | | 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index | +----+-------------+-------+------+---------------+-------------+---------+--------------------+------+---------------------------------+ 複合INDEX付与前 複合INDEX付与後 +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ | 1 | SIMPLE | Ctr | index | NULL | mul_idx1 | 55 | NULL | 1 | Using index | | 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index | +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ 実行時間 239 rows in set (0.26 sec) 実行時間 239 rows in set (0.59 sec) ※データ量増
  • 73. 5章 インデックスは万能ではない クエリ 抽出仕様 抽出項目 国コード 国名 都市数 City(都市テーブル) (件数増幅:411979) +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ Country(国テーブル) +----------+---------------+-----+ | ColumnID | ColumnName | Key | +----------+---------------+-----+ | Code | 国コード | PRI | | Name | 国名 | | ==============省略================ テーブル 抽出イメージ Ctr +------+---------------+ | Code | Name | +------+---------------+ | ATA | Antarctica | | JPN | Japan | | KOR | South Korea | | USA | United States | +------+---------------+ Cty +-------------+-----------+ | CountryCode | CityCount | +-------------+-----------+ | ABW | 2 | | JPN | 2 | | KOR | 1 | | USA | 1 | +-------------+-----------+ Ctr LEFT JOIN Sub GROUP BY Ctr_Column +-------------+---------------+-----------+ | CountryCode | CountryName | CityCount | +-------------+---------------+-----------+ | ATA | Antarctica | 0 | | JPN | Japan | 2 | | KOR | South Korea | 1 | | USA | United States | 1 | +-------------+---------------+-----------+ + = SELECT Ctr.Code CountryCode, Ctr.Name CountryName, IFNULL(Sub.CityCount, 0) CityCount FROM Country Ctr LEFT JOIN ( SELECT Cty.CountryCode, COUNT(*) CityCount FROM City Cty GROUP BY Cty.CountryCode ) Sub ON Ctr.Code = Sub.CountryCode; Sub +-------------+-----------+ | CountryCode | CityCount | +-------------+-----------+ | ABW | 2 | | JPN | 2 |○ | KOR | 1 |○ | USA | 1 |○ +-------------+-----------+ 全ての国名とその国が所有する都市数
  • 74. 5章 インデックスは万能ではない クエリの実行計画を確認してみます。 SELECT Ctr.Code CountryCode, Ctr.Name CountryName, IFNULL(Sub.CityCount, 0) CityCount FROM Country Ctr LEFT JOIN ( SELECT Cty.CountryCode, COUNT(*) CityCount FROM City Cty GROUP BY Cty.CountryCode ) Sub ON Ctr.Code = Sub.CountryCode; +----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+ | 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 245 | | | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | | | 2 | DERIVED | Cty | index | NULL | CountryCode | 3 | NULL | 412116 | Using index | +----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+ サブクエリのGROUP BYにて単一INDEXを集計キーとして使用! ※JOINがテーブルスキャンとなっているが負荷は軽微! 実行計画
  • 75. 5章 インデックスは万能ではない 複合インデックス付与版 クエリ作り直し版 +----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+ | 1 | PRIMARY | Ctr | ALL | NULL | NULL | NULL | NULL | 245 | | | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | | | 2 | DERIVED | Cty | index | NULL | CountryCode | 3 | NULL | 412116 | Using index | +----+-------------+------------+-------+---------------+-------------+---------+------+--------+-------------+ 実行時間 239 rows in set (0.16 sec) 実行時間 +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ | 1 | SIMPLE | Ctr | index | NULL | mul_idx1 | 55 | NULL | 1 | Using index | | 1 | SIMPLE | Cty | ref | CountryCode | CountryCode | 3 | world_big.Ctr.Code | 873 | Using index | +----+-------------+-------+-------+---------------+-------------+---------+--------------------+------+-------------+ 239 rows in set (0.26 sec)
  • 77. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩
  • 78. 6章 相関サブクエリは諸刃の剣 各国の最大人口を誇る都市を抽出 クエリ SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population = ( SELECT MAX(Cty2.Population) FROM City Cty2 WHERE Cty2.CountryCode = Cty1.CountryCode ); City(都市テーブル) (件数増幅:411979) +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ 抽出項目 国コード 都市名 都市人口 抽出仕様 テーブル
  • 79. 6章 相関サブクエリは諸刃の剣 クエリの実行計画を確認してみます。 SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population = ( SELECT MAX(Cty2.Population) FROM City Cty2 WHERE Cty2.CountryCode = Cty1.CountryCode ); +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 412116 | Using where | | 2 | DEPENDENT SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | world_big.Cty1.CountryCode | 873 | | +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ 相関サブクエリで構成されているため、select_typeに DEPENDENT SUBQUERYと表示されています。 +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 412116 | Using where | | 2 | DEPENDENT SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | world_big.Cty1.CountryCode | 873 | | +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ 外部クエリ サブクエリ 実行計画
  • 80. 6章 相関サブクエリは諸刃の剣 +-------------+--------------+------------+ | CountryCode | Name | Population | +-------------+--------------+------------+ ① | JPN | Tokyo | 7980230 | ② | JPN | Osaka | 2595674 | ③ | JPN | Kamakura | 167661 | ④ | CHN | Shanghai | 9696300 | ⑤ | CHN | Kunming | 1829500 | ⑥ | CHN | Dali | 136554 | ⑦ | USA | New York | 8008278 | ⑧ | USA | Houston | 1953631 | ⑨ | USA | Hollywood | 139357 | +-------------+--------------+------------+ データの内容 相関サブクエリのイメージを図示すると以下のような感じです。 ⑨ ⑧ Cty1 ② ① ⑥ ④ ⑤ ⑦ ③ Cty2 CountryCode=JPN CountryCode=CHN CountryCode=USA +-------------+--------------+------------+ | CountryCode | Name | Population | +-------------+--------------+------------+ ① | JPN | Tokyo | 7980230 | ④ | CHN | Shanghai | 9696300 | ⑦ | USA | New York | 8008278 | +-------------+--------------+------------+ クエリ実行結果 SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population = (); SELECT MAX(Cty2.Population) FROM City Cty2 WHERE Cty2.CountryCode = Cty1.CountryCode Cty1.CountryCodeで Cty2の集合を分割 MAX(Cty2.Population) +-------------+--------------+------------+ | CountryCode | Name | Population | +-------------+--------------+------------+ ① | JPN | Tokyo | 7980230 | ② | JPN | Osaka | 2595674 | ③ | JPN | Kamakura | 167661 | ④ | CHN | Shanghai | 9696300 | ⑤ | CHN | Kunming | 1829500 | ⑥ | CHN | Dali | 136554 | ⑦ | USA | New York | 8008278 | ⑧ | USA | Houston | 1953631 | ⑨ | USA | Hollywood | 139357 | +-------------+--------------+------------+
  • 81. 6章 相関サブクエリは諸刃の剣 テーブルアクセスイメージ Cty2 Cty1 row2 row1 row412115 row412116 Cty2 Cty2 Cty2 +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ | 1 | PRIMARY | Cty1 | ALL | NULL | NULL | NULL | NULL | 412116 | Using where | | 2 | DEPENDENT SUBQUERY | Cty2 | ref | CountryCode | CountryCode | 3 | world_big.Cty1.CountryCode | 873 | | +----+--------------------+-------+------+---------------+-------------+---------+----------------------------+--------+-------------+ 実行計画 row1 row2 row412115 row412116 ・ ・ ・ 873件 スキャン 873件 スキャン 873件 スキャン 873件 スキャン 359,777,268件 スキャン! 412116件 スキャン
  • 82. 6章 相関サブクエリは諸刃の剣 82 Cty2 ①SELECT 'Tokyo' , 'JPN' , 7980230 FROM City WHERE 7980230 = 7980230; ○ ②SELECT 'Osaka' , 'JPN' , 2595674 FROM City WHERE 2595674 = 7980230; ③SELECT 'Kamakura' , 'JPN' , 167661 FROM City WHERE 167661 = 7980230; ④SELECT 'Shanghai' , 'CHN' , 9696300 FROM City WHERE 9696300 = 9696300; ○ ⑤SELECT 'Kunming' , 'CHN' , 1829500 FROM City WHERE 1829500 = 9696300; ⑥SELECT 'Dali' , 'CHN' , 136554 FROM City WHERE 136554 = 9696300; ⑦SELECT 'New York' , 'USA' , 8008278 FROM City WHERE 8008278 = 8008278; ○ ⑧SELECT 'Houston' , 'USA' , 1953631 FROM City WHERE 1953631 = 8008278; ⑨SELECT 'Hollywood' , 'USA' , 139357 FROM City WHERE 139357 = 8008278; ⑨ ⑧ Cty1 ② ① ⑥ ④ ⑤ ⑦ ③ +-------------+--------------+------------+ | CountryCode | Name | Population | +-------------+--------------+------------+ ① | JPN | Tokyo | 7980230 | ② | JPN | Osaka | 2595674 | ③ | JPN | Kamakura | 167661 | ④ | CHN | Shanghai | 9696300 | ⑤ | CHN | Kunming | 1829500 | ⑥ | CHN | Dali | 136554 | ⑦ | USA | New York | 8008278 | ⑧ | USA | Houston | 1953631 | ⑨ | USA | Hollywood | 139357 | +-------------+--------------+------------+ データの内容 クエリ展開図 Cty1.CountryCode MAX(Cty2.Population) SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 WHERE Cty1.Population = (); SELECT MAX(Cty2.Population) FROM City Cty2 WHERE Cty2.CountryCode = Cty1.CountryCode 相関サブクエリの仕組み Cty1のタプル数分、 Cty2のクエリ発行を 繰り返す
  • 83. 6章 相関サブクエリは諸刃の剣 実行結果 … 返ってきません。 チューニングしましょう。
  • 84. 6章 相関サブクエリは諸刃の剣 各国の最大人口を誇る都市を抽出 クエリ City(都市テーブル) (件数増幅:411979) +-------------+------------+-----+ | ColumnID | ColumnName | Key | +-------------+------------+-----+ | ID | 都市ID | PRI | | Name | 都市名 | | | CountryCode | 国コード | MUL | | District | 地区 | | | Population | 都市人口 | MUL | +-------------+------------+-----+ 抽出項目 国コード 都市名 都市人口 抽出仕様 テーブル SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 INNER JOIN ( SELECT Cty2.CountryCode, MAX(Cty2.Population) Population FROM City Cty2 GROUP BY Cty2.CountryCode ) Sub ON Cty1.CountryCode = Sub.CountryCode AND Cty1.Population = Sub.Population; 抽出イメージ Cty1 +-------------+--------------+------------+ | CountryCode | Name | Population | +-------------+--------------+------------+ | JPN | Tokyo | 7980230 | | JPN | Osaka | 2595674 | | JPN | Kamakura | 167661 | | CHN | Shanghai | 9696300 | | CHN | Kunming | 1829500 | | CHN | Dali | 136554 | | USA | New York | 8008278 | | USA | Houston | 1953631 | | USA | Hollywood | 139357 | +-------------+--------------+------------+ Sub (Cty2) +-------------+------------+ | CountryCode | Population | +-------------+------------+ | JPN | 7980230 | | CHN | 9696300 | | USA | 8008278 | +-------------+------------+ Cty1 INNER JOIN Sub +-------------+--------------+------------+ | CountryCode | Name | Population | +-------------+--------------+------------+ | JPN | Tokyo | 7980230 | | CHN | Shanghai | 9696300 | | USA | New York | 8008278 | +-------------+--------------+------------+ + = Cty1 +-------------+--------------+------------+ | CountryCode | Name | Population | +-------------+--------------+------------+ | JPN | Tokyo | 7980230 | | JPN | Osaka | 2595674 | | JPN | Kamakura | 167661 | | CHN | Shanghai | 9696300 | | CHN | Kunming | 1829500 | | CHN | Dali | 136554 | | USA | New York | 8008278 | | USA | Houston | 1953631 | | USA | Hollywood | 139357 | +-------------+--------------+------------+
  • 85. 6章 相関サブクエリは諸刃の剣 クエリの実行計画を確認してみます。 SELECT Cty1.CountryCode, Cty1.Name, Cty1.Population FROM City Cty1 INNER JOIN ( SELECT Cty2.CountryCode, MAX(Cty2.Population) Population FROM City Cty2 GROUP BY Cty2.CountryCode ) Sub ON Cty1.CountryCode = Sub.CountryCode AND Cty1.Population = Sub.Population; +----+-------------+------------+-------+------------------------+-------------+---------+-------------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+-------+------------------------+-------------+---------+-------------------+--------+-------------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | | | 1 | PRIMARY | Cty1 | ref | CountryCode,Population | Population | 4 | Sub.Population | 1 | Using where | | 2 | DERIVED | Cty2 | index | NULL | CountryCode | 3 | NULL | 412116 | | +----+-------------+------------+-------+------------------------+-------------+---------+-------------------+--------+-------------+ 実行時間は以下の通りです。 232 rows in set (0.76 sec)
  • 87. 6章 相関サブクエリは諸刃の剣 テーブルアクセスイメージ +----+-------------+------------+-------+------------------------+-------------+---------+----------------+--------+-------------+ | id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | +----+-------------+------------+-------+------------------------+-------------+---------+----------------+--------+-------------+ | 1 | PRIMARY | <derived2> | ALL | NULL | NULL | NULL | NULL | 232 | | | 1 | PRIMARY | Cty1 | ref | CountryCode,Population | Population | 4 | Sub.Population | 1 | Using where | | 2 | DERIVED | Cty2 | index | NULL | CountryCode | 3 | NULL | 412116 | | +----+-------------+------------+-------+------------------------+-------------+---------+----------------+--------+-------------+ チューニング後の実行計画 Cty1 Cty2 derived2 412116件 スキャン 232件 232 * 1件 スキャン
  • 89. 1章 対話的にクエリを作る 2章 オプティマイザの判断 3章 サブクエリは「データ」の集合 4章 ソートとインデックス 5章 インデックスは万能ではない 6章 相関サブクエリは諸刃の剣 休憩 最後に