MySQLでの実行計画と最適化による品質の向上
この記事では、MySQLでの実行計画についての基本と考慮すべきポイントを説明し、
業務を進めるにあたりなぜ実行計画が重要なのか、
どのような形で品質の向上につなげるのかを、理解してもらうことを目的としています。
SQLクエリの実行計画と最適化
実行計画の話をする前に、SQLが実行される仕組みについて説明します。
以下はDBがSQLを受 け取ってから、データを返すまでの流れです。
上の図を見てもらうとわかる通り、SQLが実行される前に、
クエリの最適化と実行計画の作成が行われています。
SQLを実行するにあたり、この実行計画が重要な役割を担っている
イメージがついたところで、実行計画とは何かを説明していきます。
実行計画とは
実行計画とは名前の通り、SQLを実行するための計画です。
もう少し深掘って説明すると、クライアントが発行したSQLを実行するにあたり、
どのようにアクセスし、どのようにデータを探して取得するかをオプティマイザが決定し、
まとめた計画書のようなものです。
実行計画には、どのようなテーブルを使うか、
どのような順番でテーブルを結合するかなどが記載されています。
より良い実行計画の作成を意識することで、クエリのパフォーマンス向上につながります。
オプティマイザとは
MySQLのオプティマイザは、与えられたSQLクエリに対して最も効率的な実行計画を生成する
データベースエンジンのコンポーネントです。
もっと簡単に言うと、速 くて楽にデータを取得するための最適な方法を考えてくれる人です。
オプティマイザは、テーブルの統計情報、インデックスの有効性、クエリの構造、
利用可能なシステムリソースなどを考慮して、複数の可能な実行パスの中から最適なものを選択します。
この過程により、クエリの実行時間が最小限に抑えられ、データベースの全体的なパフォーマンスが向上します。
ですが、オプティマイザはいつでも最適な実行計画を生成してくれるわけではありません。
そのため、まずはオプティマイザが生成した実行計画を確認し、思ってた実行計画と違う場合は、
こちらで手を加えてあげる必要があります。
クエリの最適化
オプティマイザが良い実行計画を作ってくれるために、クエリの最適化は必要不可欠です。
クエリの最適化とは、SQLクエリを効率的に実行するためのプロセスです。
これには、データ取得方法の改善、不要な処理の削減、
効率的なインデックスの使用、クエリの再構成などが含まれます。
最適化の目的は、クエリの実行時間を短縮し、データベースのリソース使用を最小限に抑えることです。
クエリの最適化は、適切なインデックスの作成、クエリの書き直し、不要な結合の削除、
集約操作の効率化などを通じて実現されます。
また、データベースの設定を調整すること でもパフォーマンスが向上することがあります。
ここまで、実行計画についての基本を説明してきました。
それでは実際にEXPLAINを使って実行計画を確認してみましょう。
実行計画の確認
今回使うテーブルは以下の通りです。
実行計画を確認するため、データは大量に入れておきます。
employees (従業員:100万件)
| id | name | department_id | hire_date | fired_date |
|---|---|---|---|---|
| 1 | 田中 太郎 | 1 | 2000-01-01 | null |
| 2 | 桜木 花道 | 1 | 2001-01-01 | 2001-01-17 |
departments (部署:20件)
| id | name | start_date |
|---|---|---|
| 1 | 人事部 | 2000-01-01 |
projects (プロジェクト:100件)
| id | name | start_date | end_date |
|---|---|---|---|
| 1 | 株式会社 マリンフォード | 2000-01-01 | 2000-01-31 |
| 2 | 有限会社 ウォールシーナ | 2000-01-01 | null |
employee_projects (従業員とプロジェクトの中間テーブル:100万件)
| id | employee_id | project_id |
|---|---|---|
| 1 | 14533 | 155 |
employee_idとproject_idは、employeesテーブルとprojectsテーブルのidの外部キーです。
EXPLAIN
MySQLでクエリの実行計画を確認するには、SQLクエリの先頭にEXPLAINを付けて実行します。
試しにemployeesテーブルから苗字が「田中」の従業員を取得するクエリを実行してみましょう。
EXPLAIN SELECT * FROM employees WHERE name LIKE '田中%';
この結果、以下のような実行計画が表示されます。
| id | select_type | table | partitions | type | possible_keys | key | fkey_len | ref | rows | filtered | Extra |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | SIMPLE | employees | null | ALL | null | null | null | null | 1000000 | 100.00 | Using where |
| カラム名 | 意味 |
|---|---|
| id | クエリ内のテーブルの実行順序 |
| select_type | クエリの種類 |
| table | クエリ内のテーブル名 |
| partitions | クエリ内のテーブルのパーティション名 |
| type | クエリ内のテーブルのアクセス方法 |
| possible_keys | クエリ内のテーブルのインデックス |
| key | クエリ内のテーブルの実際に使用されたインデックス |
| key_len | クエリ内のテーブルのインデックスの長さ |
| ref | クエリ内のテーブルの参照先 |
| rows | クエリ内のテーブルのスキャンする行数 |
| filtered | クエリ内のテーブルのフィルタリングされた行数 |
| Extra | クエリ内のテーブルの追加情報 |