SlideShare a Scribd company logo
MySQL におけるSQLチューニング
はじめに
この資料では以下について説明します。
• MySQL でスロークエリを抽出する。
• SQL実行計画を調べる。
• SQL実行計画を改善する。
スロークエリ (1)
mysqlのコンソールからshow variablesコマンドで、スロークエリの設定を確認で
きます。以下の設定だと /var/log/mysql/slow-query.log にスロークエリを出力し
ます。
mysql> show variables like 'slow%';
+---------------------+-------------------------------+
| Variable_name | Value |
+---------------------+-------------------------------+
| slow_launch_time | 2 |
| slow_query_log | ON |
| slow_query_log_file | /var/log/mysql/slow-query.log |
+---------------------+-------------------------------+
→ slow_query_log がOFFになっているとスロークエリの出力は行われません。
スロークエリ (2)
slow_query_logがONのとき、long_query_timeを超えるクエリがスロークエリ
として出力されます。単位は秒です。以下の設定だと、処理が1秒以上かか
るSQLがスロークエリログに出力されます。
mysql> show variables like 'long%';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 1.000000 |
+-----------------+----------+
スロークエリ (3)
スロークエリの判定時間の変更はmysqlコンソールから以下のように行ないま
す。
mysql> set global long_query_time = 0.001; (← 1msecの例)
確認するには一度quitしてから再度mysqlコンソールに接続し、以下で確認します。
mysql> show variables like 'long%';
+-----------------+----------+
| Variable_name | Value |
+-----------------+----------+
| long_query_time | 0.001000 |
+-----------------+----------+
→ long_query_timeで指定した秒数以上のスロークエリが、slow_query_log_file
で指定されたファイルに出力されていることを確認します。
mysqldumpslow
mysqldumpslow は、MySQL スロークエリーログファイルを解析して内容のサ
マリーを出力します。
使用例.
$ mysqldumpslow –a /var/log/mysql/slow-query.log > slow-query_collected.log
$ cat slow-query_collected.log
Count: 1 Time=4.32s (4s) Lock=0.00s (0s) Rows=0.0 (0), root[root]@localhost
insert into t2 select * from t1
Count: 3 Time=2.53s (7s) Lock=0.00s (0s) Rows=0.0 (0), root[root]@localhost
insert into t2 select * from t1 limit N
Count: 3 Time=2.13s (6s) Lock=0.00s (0s) Rows=0.0 (0), root[root]@localhost
insert into t1 select * from t1
※ デフォルトでは mysqldumpslow は平均クエリー時間でソートします。
mysqldumpslowのオプションについては以下を参照ください。
https://dev.mysql.com/doc/refman/5.6/ja/mysqldumpslow.html
explain
抽出した遅いSQLの実行計画をexplainで表示します。
mysql> explain <SQL>;
注意: MySQLではデフォルトautocommitをONとしているためDMLを実行するとロール
バックできません。そのためDML (INSERT, UPDATE文, DELETE) はexplainを忘れて実
行するとデータが変更されてしまいます。したがってDMLの調査は注意する必要が
あります。
⇒ UPDATE, DELETEはexplainの際にSELECT文に置き換えておくのが安全です。
explainのそれぞれの項目について (1)
● select_typeの詳細
EXPLAIN からの各出力行は 一つのテーブルに関する情報を提供します。各行の説明は 表8.1「EXPLAIN
出力カラム」のとおりです。
表 8.1 EXPLAIN 出力カラム
カラム 意味
id SELECT 識別子。
select_type SELECT 型
table 出力行のテーブル
partitions 一致するパーティション
type 結合型
possible_keys 選択可能なインデックス
key 実際に選択されたインデックス
key_len 選択されたキーの長さ
ref インデックスと比較されるカラム
rows 調査される行の見積もり
filtered テーブル条件によってフィルタ処理される行の割合
Extra 追加情報
⇒ type, key, rowsが重要な情報です。一方、possible_keysはそれほど重要ではありません。
explainのそれぞれの項目について (2)
● select_typeの詳細
• SIMPLE
– 単一のテーブル
• サブクエリが絡む場合
– PRIMARY
• 外部クエリ
– SUBQUERY
• 相関関係の無いサブクエリ
– DEPENDENT SUBQUERY
• 相関関係のあるサブクエリ
– UNCACHEABLE SUBQUERY
• 実行する度に結果が変わる可能性のあるサブクエリ
– DERIVED
• FROM句で用いられているサブクエリ
● table
• 対象テーブルの名称
explainのそれぞれの項目について (3)
● typeの詳細
• const
– pk or uniqueインデックスを使用したルックアップによるアクセス
– 最も速い
• eq_ref
– joinにおいてのconstと同義
• ref
– constでないインデックスを使って等価検索(where k = v)を行った時に使用されるアクセス
• range
– indexを用いた範囲検索
• index
– フルインデックススキャン、インデックス全体をスキャンしているので遅い
• ALL
– フルテーブルスキャン、インデックスが全く使用されていないことを示す
⇒ チューニングでは(インデックスを調整するなどして) explain結果のtypeに “index”, “ALL” が表示されないよ
うにすることが重要です。
⇒ のRDBでは表に対し複合インデックスが作成されていることが多いのですが、これらのインデックスは適切に
使用されていないことがあります。そのような場合 “index”が表示され、rowsに大きな値が入ります。最低限の
列単独のインデックス、最小限の列をもつ複合インデックスを用意する必要があります。
explainのそれぞれの項目について (4)
● possible_keys
• optimizerがテーブルのアクセスに利用可能だと判断したインデックス
● key
• 実際にoptimizerによって使用されたキー
● key_len
• 選択されたキーの長さ。長さは短いほうが高速。
● ref
• 検索条件でkeyと比較されている値やカラムの種類。
– 定数の場合
• const
– JOINを使用している場合
• 結合する相手側のテーブルで検索条件として利用されているカラムが表示される
● rows
• そのテーブルからfetchされる行数の見積もり。これが大きいとインデックスが適切に使われていない可能
性が大きい。
• 大まかな見積もりなので、実際にfetchする行数とは変わる可能性がある。
– しかしDERIVEDテーブルだけは実際に実行しないと行数の見積もりができないので、DERIVEDテーブル
の見積もりだけは正確
explainのそれぞれの項目について (5)
● Extraフィールドに表示される代表的な追加情報を以下に挙げる。これらの情報は同時に複数表示される場合が
ある。
• Using where・・・頻繁に出力される追加情報である。WHERE句に検索条件が指定されており、なおかつインデック
スを見ただけではWHERE句の条件を全て適用することが出来ない場合に表示される。
• Using index・・・クエリがインデックスだけを用いて解決できることを示す。Covering Indexを利用している場合など
に表示される。
• Using filesort・・・filesort(クイックソート)でソートを行っていることを示す。
• Using temporary・・・JOINの結果をソートしたり、DISTINCTによる重複の排除を行う場合など、クエリの実行にテン
ポラリテーブルが必要なことを示す。
• Using index for group-by・・・MIN()/MAX()がGROUP BY句と併用されているとき、クエリがインデックスだけを用い
て解決できることを示す。
• Range checked for each record (index map: N)・・・JOINにおいてrangeまたはindex_mergeが利用される場合に表
示される。
• Not exists・・・LEFT JOINにおいて、左側のテーブルからフェッチされた行にマッチする行が右側のテーブルに存在
しない場合、右側のテーブルはNULLとなるが、右側のテーブルがNOT NULLとして定義されたフィールドでJOINさ
れている場合にはマッチしない行を探せば良い・・・ということを示す。
詳しくは以下をご確認ください:
https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-extra-information (MySQL5.7)
https://dev.mysql.com/doc/refman/5.6/ja/explain-output.html#explain-extra-information (MySQL5.6; 日本語訳)
show index
・show index は、テーブルのインデックス情報を返します。show indexで、スロークエリの対象となるテーブルに追加すべきインデックスが
あるか、不要なインデックスがないか調査します。SHOW INDEX は、次のフィールドを返します。
( https://dev.mysql.com/doc/refman/5.6/ja/show-index.html )
Table: テーブルの名前。
Non_unique: このインデックスが重複を含むことができない場合は 0で、できる場合は 1です。
Key_name: インデックスの名前。このインデックスが主キーである場合、その名前は常に PRIMARY です。
Seq_in_index: インデックス内のカラムシーケンス番号であり、1 から始まります。
Column_name: カラム名。
Collation: インデックス内でのカラムのソート方法。MySQL では、これは「A」(昇順) またはNULL(ソートされない) のどちらかの値です。
Cardinality: このインデックス内の一意の値の数の推定値。これは、ANALYZE TABLE を実行することによって更新されます。Cardinality は
整数として格納された統計に基づいてカウントされるため、この値は、小さなテーブルの場合でも必ずしも正確であるとはかぎりません。
カーディナリティーが高いほど、MySQL が結合を実行するときにこのインデックスを使用する可能性は高くなります。
Sub_part: カラムが部分的にしかインデックス設定されていない場合は、インデックス設定された文字の数を示します。カラム全体がイン
デックス設定されている場合は NULLです。
Null: このカラムに NULL 値を含めることができる場合は YES が、できない場合は '' が含まれます。
Index_type: 使用されるインデックス方法 (BTREE, FULLTEXT, HASH, RTREE)
スロークエリの改善方法
(1) long_query_time を変更します。
例.
mysql> set global long_query_time = 0.000001; (← 1 マイクロ秒以上のSQLをログ出力する場合)
(2) スロークエリを取得したい画面の操作を行ないます。
(3) slow_query_log_file で指定されたファイルにスロークエリが出力されたことを確認します。
(4) long_query_time を元に戻します。
例.
mysql> set global long_query_time = 1; (← 1秒に戻す場合)
(5) mysqldumpslow でスロークエリを抽出します。
$ mysqldumpslow –a slow-query.log > slow-query-<YYYYMMDD>.log
(6) 抽出したスロークエリをexplain実行計画をexplainで表示します。カーディナリティが高い列に対してインデッ
クスが有効に使用されていないようであればインデックスの追加等を検討します。
(7) (6)のSQLの対象のテーブルのインデックスを show index from <table名> で調査し、不要なインデック
スは削除を検討します。また、複合インデックスに不要な列があるようであればインデックスの再定義を
検討します。
まとめ
• MySQL でスロークエリをログに出力する。
• mysqldumpslow でスロークエリを抽出する。
• explainでSQL実行計画を調べる。
• show index でインデックスを調査する。
• SQL実行計画を改善する。
参考文献
• https://use-the-index-luke.com/ja 開発者のためのSQLのチューニン
グへのガイド
• https://qiita.com/kzbandai/items/ea02727f4bb539fcedb5
• http://nippondanji.blogspot.com/2009/03/mysqlexplain.html

More Related Content

PDF
とあるDBAの黒い画面(ターミナル)
PDF
とあるDBAの黒い画面(ターミナル)II
PDF
MySQL8.0 SYS スキーマ概要
PDF
Slub alloc and free
PDF
MySQL SYSスキーマのご紹介
PDF
Slub data structure
ODP
Mysql(クライアント)の出力が変わるオプション達
PDF
db tech showcase 2019 D10 Oracle Database New Features
とあるDBAの黒い画面(ターミナル)
とあるDBAの黒い画面(ターミナル)II
MySQL8.0 SYS スキーマ概要
Slub alloc and free
MySQL SYSスキーマのご紹介
Slub data structure
Mysql(クライアント)の出力が変わるオプション達
db tech showcase 2019 D10 Oracle Database New Features

Similar to MySQL SQL tuning (20)

PPT
20090107 Postgre Sqlチューニング(Sql編)
PDF
2019年度 若手技術者向け講座 実行計画
PDF
PostgreSQL10徹底解説
PDF
Let's scale-out PostgreSQL using Citus (Japanese)
PDF
Lisp Tutorial for Pythonista : Day 4
PDF
2019年度 若手技術者向け講座 DBMSの機能
PPTX
SQLチューニング入門 入門編
PDF
AWS Black Belt Tech シリーズ 2015 - Amazon Redshift
PDF
Linux 対応だけじゃない!! sql server 2017 こんな機能が追加されています。
PDF
KOF2015 PostgreSQL 9.5
PDF
Pgunconf 20121212-postgeres fdw
PDF
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
PDF
アナリティクスをPostgreSQLで始めるべき10の理由@第6回 関西DB勉強会
PDF
Chugoku db 20th-postgresql-10-pub
PPT
HandlerSocket plugin for MySQL
PDF
Scala2.8への移行
PDF
Scala2.8への移行
PDF
Ntt tx-study-postgre sql-10
PDF
はじめてのAmazon Redshift
PDF
20160929 inno db_fts_jp
20090107 Postgre Sqlチューニング(Sql編)
2019年度 若手技術者向け講座 実行計画
PostgreSQL10徹底解説
Let's scale-out PostgreSQL using Citus (Japanese)
Lisp Tutorial for Pythonista : Day 4
2019年度 若手技術者向け講座 DBMSの機能
SQLチューニング入門 入門編
AWS Black Belt Tech シリーズ 2015 - Amazon Redshift
Linux 対応だけじゃない!! sql server 2017 こんな機能が追加されています。
KOF2015 PostgreSQL 9.5
Pgunconf 20121212-postgeres fdw
今からでも遅くないDBマイグレーション - Flyway と SchemaSpy の紹介 -
アナリティクスをPostgreSQLで始めるべき10の理由@第6回 関西DB勉強会
Chugoku db 20th-postgresql-10-pub
HandlerSocket plugin for MySQL
Scala2.8への移行
Scala2.8への移行
Ntt tx-study-postgre sql-10
はじめてのAmazon Redshift
20160929 inno db_fts_jp
Ad

More from Tetsuro Nagae (7)

PPTX
オブザーバビリティ、OpenTelemetryについて.pptx
PPTX
RDBのインデックスについて.pptx
PDF
Hoare論理
PDF
Purely functional data structures 8.2 日本語での説明
PPT
Blueprintsについて
PDF
purely functional data structures 5.3 日本語での説明
PDF
Purely Functional Data Structures ex3.3 leftist heap
オブザーバビリティ、OpenTelemetryについて.pptx
RDBのインデックスについて.pptx
Hoare論理
Purely functional data structures 8.2 日本語での説明
Blueprintsについて
purely functional data structures 5.3 日本語での説明
Purely Functional Data Structures ex3.3 leftist heap
Ad

MySQL SQL tuning

  • 3. スロークエリ (1) mysqlのコンソールからshow variablesコマンドで、スロークエリの設定を確認で きます。以下の設定だと /var/log/mysql/slow-query.log にスロークエリを出力し ます。 mysql> show variables like 'slow%'; +---------------------+-------------------------------+ | Variable_name | Value | +---------------------+-------------------------------+ | slow_launch_time | 2 | | slow_query_log | ON | | slow_query_log_file | /var/log/mysql/slow-query.log | +---------------------+-------------------------------+ → slow_query_log がOFFになっているとスロークエリの出力は行われません。
  • 5. スロークエリ (3) スロークエリの判定時間の変更はmysqlコンソールから以下のように行ないま す。 mysql> set global long_query_time = 0.001; (← 1msecの例) 確認するには一度quitしてから再度mysqlコンソールに接続し、以下で確認します。 mysql> show variables like 'long%'; +-----------------+----------+ | Variable_name | Value | +-----------------+----------+ | long_query_time | 0.001000 | +-----------------+----------+ → long_query_timeで指定した秒数以上のスロークエリが、slow_query_log_file で指定されたファイルに出力されていることを確認します。
  • 6. mysqldumpslow mysqldumpslow は、MySQL スロークエリーログファイルを解析して内容のサ マリーを出力します。 使用例. $ mysqldumpslow –a /var/log/mysql/slow-query.log > slow-query_collected.log $ cat slow-query_collected.log Count: 1 Time=4.32s (4s) Lock=0.00s (0s) Rows=0.0 (0), root[root]@localhost insert into t2 select * from t1 Count: 3 Time=2.53s (7s) Lock=0.00s (0s) Rows=0.0 (0), root[root]@localhost insert into t2 select * from t1 limit N Count: 3 Time=2.13s (6s) Lock=0.00s (0s) Rows=0.0 (0), root[root]@localhost insert into t1 select * from t1 ※ デフォルトでは mysqldumpslow は平均クエリー時間でソートします。 mysqldumpslowのオプションについては以下を参照ください。 https://dev.mysql.com/doc/refman/5.6/ja/mysqldumpslow.html
  • 7. explain 抽出した遅いSQLの実行計画をexplainで表示します。 mysql> explain <SQL>; 注意: MySQLではデフォルトautocommitをONとしているためDMLを実行するとロール バックできません。そのためDML (INSERT, UPDATE文, DELETE) はexplainを忘れて実 行するとデータが変更されてしまいます。したがってDMLの調査は注意する必要が あります。 ⇒ UPDATE, DELETEはexplainの際にSELECT文に置き換えておくのが安全です。
  • 8. explainのそれぞれの項目について (1) ● select_typeの詳細 EXPLAIN からの各出力行は 一つのテーブルに関する情報を提供します。各行の説明は 表8.1「EXPLAIN 出力カラム」のとおりです。 表 8.1 EXPLAIN 出力カラム カラム 意味 id SELECT 識別子。 select_type SELECT 型 table 出力行のテーブル partitions 一致するパーティション type 結合型 possible_keys 選択可能なインデックス key 実際に選択されたインデックス key_len 選択されたキーの長さ ref インデックスと比較されるカラム rows 調査される行の見積もり filtered テーブル条件によってフィルタ処理される行の割合 Extra 追加情報 ⇒ type, key, rowsが重要な情報です。一方、possible_keysはそれほど重要ではありません。
  • 9. explainのそれぞれの項目について (2) ● select_typeの詳細 • SIMPLE – 単一のテーブル • サブクエリが絡む場合 – PRIMARY • 外部クエリ – SUBQUERY • 相関関係の無いサブクエリ – DEPENDENT SUBQUERY • 相関関係のあるサブクエリ – UNCACHEABLE SUBQUERY • 実行する度に結果が変わる可能性のあるサブクエリ – DERIVED • FROM句で用いられているサブクエリ ● table • 対象テーブルの名称
  • 10. explainのそれぞれの項目について (3) ● typeの詳細 • const – pk or uniqueインデックスを使用したルックアップによるアクセス – 最も速い • eq_ref – joinにおいてのconstと同義 • ref – constでないインデックスを使って等価検索(where k = v)を行った時に使用されるアクセス • range – indexを用いた範囲検索 • index – フルインデックススキャン、インデックス全体をスキャンしているので遅い • ALL – フルテーブルスキャン、インデックスが全く使用されていないことを示す ⇒ チューニングでは(インデックスを調整するなどして) explain結果のtypeに “index”, “ALL” が表示されないよ うにすることが重要です。 ⇒ のRDBでは表に対し複合インデックスが作成されていることが多いのですが、これらのインデックスは適切に 使用されていないことがあります。そのような場合 “index”が表示され、rowsに大きな値が入ります。最低限の 列単独のインデックス、最小限の列をもつ複合インデックスを用意する必要があります。
  • 11. explainのそれぞれの項目について (4) ● possible_keys • optimizerがテーブルのアクセスに利用可能だと判断したインデックス ● key • 実際にoptimizerによって使用されたキー ● key_len • 選択されたキーの長さ。長さは短いほうが高速。 ● ref • 検索条件でkeyと比較されている値やカラムの種類。 – 定数の場合 • const – JOINを使用している場合 • 結合する相手側のテーブルで検索条件として利用されているカラムが表示される ● rows • そのテーブルからfetchされる行数の見積もり。これが大きいとインデックスが適切に使われていない可能 性が大きい。 • 大まかな見積もりなので、実際にfetchする行数とは変わる可能性がある。 – しかしDERIVEDテーブルだけは実際に実行しないと行数の見積もりができないので、DERIVEDテーブル の見積もりだけは正確
  • 12. explainのそれぞれの項目について (5) ● Extraフィールドに表示される代表的な追加情報を以下に挙げる。これらの情報は同時に複数表示される場合が ある。 • Using where・・・頻繁に出力される追加情報である。WHERE句に検索条件が指定されており、なおかつインデック スを見ただけではWHERE句の条件を全て適用することが出来ない場合に表示される。 • Using index・・・クエリがインデックスだけを用いて解決できることを示す。Covering Indexを利用している場合など に表示される。 • Using filesort・・・filesort(クイックソート)でソートを行っていることを示す。 • Using temporary・・・JOINの結果をソートしたり、DISTINCTによる重複の排除を行う場合など、クエリの実行にテン ポラリテーブルが必要なことを示す。 • Using index for group-by・・・MIN()/MAX()がGROUP BY句と併用されているとき、クエリがインデックスだけを用い て解決できることを示す。 • Range checked for each record (index map: N)・・・JOINにおいてrangeまたはindex_mergeが利用される場合に表 示される。 • Not exists・・・LEFT JOINにおいて、左側のテーブルからフェッチされた行にマッチする行が右側のテーブルに存在 しない場合、右側のテーブルはNULLとなるが、右側のテーブルがNOT NULLとして定義されたフィールドでJOINさ れている場合にはマッチしない行を探せば良い・・・ということを示す。 詳しくは以下をご確認ください: https://dev.mysql.com/doc/refman/5.7/en/explain-output.html#explain-extra-information (MySQL5.7) https://dev.mysql.com/doc/refman/5.6/ja/explain-output.html#explain-extra-information (MySQL5.6; 日本語訳)
  • 13. show index ・show index は、テーブルのインデックス情報を返します。show indexで、スロークエリの対象となるテーブルに追加すべきインデックスが あるか、不要なインデックスがないか調査します。SHOW INDEX は、次のフィールドを返します。 ( https://dev.mysql.com/doc/refman/5.6/ja/show-index.html ) Table: テーブルの名前。 Non_unique: このインデックスが重複を含むことができない場合は 0で、できる場合は 1です。 Key_name: インデックスの名前。このインデックスが主キーである場合、その名前は常に PRIMARY です。 Seq_in_index: インデックス内のカラムシーケンス番号であり、1 から始まります。 Column_name: カラム名。 Collation: インデックス内でのカラムのソート方法。MySQL では、これは「A」(昇順) またはNULL(ソートされない) のどちらかの値です。 Cardinality: このインデックス内の一意の値の数の推定値。これは、ANALYZE TABLE を実行することによって更新されます。Cardinality は 整数として格納された統計に基づいてカウントされるため、この値は、小さなテーブルの場合でも必ずしも正確であるとはかぎりません。 カーディナリティーが高いほど、MySQL が結合を実行するときにこのインデックスを使用する可能性は高くなります。 Sub_part: カラムが部分的にしかインデックス設定されていない場合は、インデックス設定された文字の数を示します。カラム全体がイン デックス設定されている場合は NULLです。 Null: このカラムに NULL 値を含めることができる場合は YES が、できない場合は '' が含まれます。 Index_type: 使用されるインデックス方法 (BTREE, FULLTEXT, HASH, RTREE)
  • 14. スロークエリの改善方法 (1) long_query_time を変更します。 例. mysql> set global long_query_time = 0.000001; (← 1 マイクロ秒以上のSQLをログ出力する場合) (2) スロークエリを取得したい画面の操作を行ないます。 (3) slow_query_log_file で指定されたファイルにスロークエリが出力されたことを確認します。 (4) long_query_time を元に戻します。 例. mysql> set global long_query_time = 1; (← 1秒に戻す場合) (5) mysqldumpslow でスロークエリを抽出します。 $ mysqldumpslow –a slow-query.log > slow-query-<YYYYMMDD>.log (6) 抽出したスロークエリをexplain実行計画をexplainで表示します。カーディナリティが高い列に対してインデッ クスが有効に使用されていないようであればインデックスの追加等を検討します。 (7) (6)のSQLの対象のテーブルのインデックスを show index from <table名> で調査し、不要なインデック スは削除を検討します。また、複合インデックスに不要な列があるようであればインデックスの再定義を 検討します。
  • 15. まとめ • MySQL でスロークエリをログに出力する。 • mysqldumpslow でスロークエリを抽出する。 • explainでSQL実行計画を調べる。 • show index でインデックスを調査する。 • SQL実行計画を改善する。
  • 16. 参考文献 • https://use-the-index-luke.com/ja 開発者のためのSQLのチューニン グへのガイド • https://qiita.com/kzbandai/items/ea02727f4bb539fcedb5 • http://nippondanji.blogspot.com/2009/03/mysqlexplain.html