SQL自体を記述出来るエンジニアは多いですが、パフォーマンスのことまで考慮したSQL文を作成出来るエンジニアというのは意外と少ないものです。
今回はSQLのパフォーマンスを改善するために、エンジニアがデータベース処理を実装する際、意識しておきたいポイントをご紹介していきたいと思います。
目次
SQLのパフォーマンスを改善するには?!
SQLのパフォーマンスを改善するためには、基本となるポイントを抑えた上で、パフォーマンスを意識したSQL文を記述することが重要になります。
今回は少しの意識だけで簡単に改善出来る、SQLのパフォーマンス改善ポイントについてご紹介していきたいと思います。
- SELECT句の「*」
- 複合インデックス
- WHERE句の条件指定順
- テーブルに別名を付ける
- LIKE句のワイルドカード
SQLパフォーマンス改善1: SELECT句の「*」
多くの方が利用するテーブルの全てのカラムを取得する「*」ですが、実はカラム数が多いとSQLのパフォーマンスに影響を与えていることも少なくありません。
利用しないカラムまで「*」で取得しているような場合には、必要なカラムだけを取得するように変更するだけでもパフォーマンスの向上が期待出来ます。
サンプル
例えば「column1」~「column5」まで定義されているテーブルで、実際に利用するカラムは「column1」と「column4」だけの場合には下記のように変更します。
変更前
SELECT * FROM sample_table;
変更後
SELECT column1, column4 FROM sample_table;
SQLパフォーマンス改善2: 複合インデックス
複合インデックスを指定した場合、条件に指定するカラムをインデックスに定義したカラム順で指定しないと、インデックスが効かないといった問題が起こります。
インデックスを効かせるためには、インデックスで定義された順番と同じ順序で条件式を指定するようにしましょう。
サンプル
まずはCREATE文でサンプル用のテーブルを作成します。
CREATE TABLE sample1(column1 int, column2 varchar(30), column3 int, column4 int);
次に作成したテーブルに複合インデックスを付与します。
ALTER TABLE sample1 ADD INDEX(column1, column3, column4);
条件指定したSQLを作成してみましょう。
複合インデックスが有効な記述
まずは複合インデックスが有効な条件式です。
SELECT column1, column2 FROM sample1 WHERE column1 = 1 AND column3 = 2 AND column4 = 3;
複合インデックスで定義した通りの順番なので、インデックスは有効に働きます。
ちなみに「WHERE column1 = 1」や「WHERE column1 = 1 AND column3 = 2」など、全ての複合インデックスを条件と指定していなくても、順序さえ守られていれば有効です。
複合インデックスが無効な記述
上述したSQLの条件を例えば下記のように反対にするとインデックスは利用されません。
SELECT column1, column2 FROM sample1 WHERE column4 = 3 AND column3 = 2 AND column1 = 1;
SQLパフォーマンス改善3: WHERE句の条件指定順
WHERE句で複数条件を指定する場合、記述した順番に処理が実施されていきます。
そのため、最初に絞り込んだ際の結果が少なくなる条件を指定した方が、後述の条件に掛かる負担が少なくなります。
サンプル
例えばテーブルに1000件のデータが入っているとして、「年齢」と「性別」のカラムが存在するとします。
イメージとしては、下記のようなテーブルです。。
+------+-----------------+------+------+ | id | name | age | sex | +------+-----------------+------+------+ | 1 | 山田太郎 | 30 | 男 | | 2 | 山田花子 | 25 | 女 | | 3 | 鈴木二郎 | 20 | 男 | | 4 | 田中はじめ | 40 | 男 | | 5 | 田中ひかり | 19 | 女 | | etc | etc | etc | etc | +------+-----------------+------+------+
性別を先に指定
SELECT id, name FROM テーブル名 WHERE sex = '男' AND age = 30;
この場合、性別を先に絞り込んでいるため、単純に男女同数のデータが存在するテーブルであれば半分のデータが残ってしまいます。
年齢を先に指定
SELECT id, name FROM テーブル名 WHERE age = 30 AND sex = '男';
一方で、年齢を先に指定した場合、半分よりも少ないデータになることは間違いありません。
このようにWHERE句の条件指定が複数存在する場合には、絞り込んだ結果が少なくなるような条件を先に記述した方が、SQLのパフォーマンスが上がります。
SQLパフォーマンス改善4: テーブルに別名を付ける
SQLは実行時に解析が行われますが、テーブルに別名を付けた上で、全ての列名に接頭辞を付けた方が処理が早くなるようです。
サンプル
シンプルにテーブルの別名有無で確認してみましょう。
非推奨
SELECT カラム名1, カラム名2 FORM テーブル名1 INNER JOIN テーブル名2 ON カラム名 = カラム名 WHERE カラム名1 = '1';
このように、カラム名の取得元テーブルをデータベースに判断させるのでは処理が遅くなります。
推奨
SELECT alias1.カラム名1, alias2.カラム名2 FORM テーブル名1 AS alias1 INNER JOIN テーブル名2 AS alias2 ON alias2.カラム名 = alias1.カラム名 WHERE alias1.カラム名1 = '1';
推奨で記述したSQLのように、テーブル名に別名を割り当ててカラムの接頭辞全てに指定してあげると、SQLの解析が早くなるようです。
SQLパフォーマンス改善5: LIKEのワイルドカード
WHERE句の条件で「LIKE」を利用する場合にも、インデックスが無効になってしまう可能性があります。
LIKEで指定したカラムにインデックスが設定されている場合、%(ワイルドカード)の前までしか走査されません。
サンプル
3つのWHERE句の条件でインデックスの走査範囲を確認してみます。
ワイルドカードが末尾
WHERE カラム名 LIKE 'abcde%';
ワイルドカードが末尾に指定されている場合には、インデックスが「abcde」全てに効きます。
ワイルドカードが真ん中
WHERE カラム名 LIKE 'abc%de';
ワイルドカードが真ん中に指定されている場合、ワイルドカードの前方(abc)までしか効かないことになります。
ワイルドカードが先頭
WHERE カラム名 LIKE '%abcde';
ワイルドカードが先頭に指定されている場合には、インデックスが全く効かない結果となります。
LIKEの場合は、上述したパフォーマンス改善方法と異なり条件指定のため、気軽に変更出来るものでもありません。
知識として抑えておき、どうしてもパフォーマンスを改善するために必要な場合は、別の記述方法を検討するくらいでも良いかも知れません。
さいごに:パフォーマンスの高いSQL文を実装出来るように意識しよう!
本記事では、SQLのパフォーマンス改善方法として、初心者向けに基本的な手法をご紹介してきました。
SQLのパフォーマンスチューニングは非常に奥の深い分野で、今回ご紹介した内容は入り口であり、まだまだ様々なチューニング方法が存在します。
これまで必要なデータが取得さえ出来ていれば、SQLのパフォーマンスに関しては意識してなかったという方は、ぜひ今回ご紹介した内容から始めて、徐々により高度な知識を身につけて、パフォーマンスの高いSQL文を記述出来るように取り組んでみてください。
データベース毎にオプティマイザが異なるため、一概に全てのデータベースで有効とは言えませんが、一般的に挙げられている改善ポイントをご紹介していきます。