以前のアカウントがどこかへいってしまったので作り直しをしました。
最近業務でSQLを触る機会が多く、少し勉強をしたのでメモ書き程度ですが書いてみました。
サブクエリはINよりもEXISTSを使用する
-- 遅い
SELECT *
FROM ClassA
WHERE id IN (SELECT id FROM ClassB);
-- 速い
SELECT *
FROM CLASSA A
WHERE EXISTS
(SELECT *
FROM ClassB B
WHERE A.id = B.id);
- idにindexが貼られていればClassBは見に行かずインデックスを参照するのみで済む
- EXISTSは1行でも一致する行を見つけるとここで検索を打ち切るから全検索にならない
サブクエリよりも結合を使う
SELECT A.id, A.name
FROM ClassA A
INNER JOIN ClassB B
ON A.id = B.id
- どちららかのindexが必ず効いてくる
ソートを回避する
GROUP BY、ORDER BY、DISTINCTなどソートが発生するものは注意が必要になる
重複を気にしなくていい場合はUNIONの代わりにUNION ALLを使うようにする
SELECT *
FROM ClassA
UNION ALL
SELECT * FROM ClassB
DISTINCT(重複を省く)をEXISTSで代用する
-- 遅い
SELECT DISTINCT I.no
FROM Items I
INNER JOIN SalesHistory SH ON I.no = SH.no
-- 速い
SELECT I.no
FROM Items I
WHERE EXISTS (
SELECT * FROM SalesHistory SH
WHERE I.no = SH.no
)
MAX/MINでINDEXを使う
-- indexを利用していない
SELECT MAX(item)
FROM Items;
-- indexを利用している
SELECT MAX(item_no)
FROM Items;
- item_noは主キーなのでより効果的にindexを使用できている
WHERE句出かけるものはHAVING句に書かない
以下のSQLはどちらも同じ結果になるが、後者の方が速い
-- 遅い
SELECT sales_date, SUM(quanitity)
FROM SalesHistory
GROUP BY sales_date
HAVING sale_date = '2023-09-01';
-- 速い
SELECT sales_date, SUM(quanitity)
FROM SalesHistory
WHERE sales_date = '2023-09-01'
GROUP BY sales_date;
- GROUP BYはWHEREで指定された後に行うのでなるべくレコード数を絞り込んだ方がいい
- WHEREでindexをを利用できる
indexを正しく使おう
indexを貼ってはいるものの、理解した上で使わないと上手く使えていないこともある
加工を行なっている
計算式を使っている場合、左辺ではなく右辺で計算するようにする
-- indexを利用していない
SELECT *
FROM SomeTable
WHERE col_1 * 3 > 100;
-- indexを利用している
SELECT *
FROM SomeTable
WHERE col_1 > 100 / 3;
NULLが存在する
基本的にNULLが存在しているカラムには、indexを貼るべきではないと考えている
以下は応急処置程度で考えるといい
-- index利用していない
SELECT *
FROM SomeTable
WHERE col_1 IS NOT NULL
-- indexを利用している
SELECT *
FROM SomeTable
WHERE col_1 > 0;
否定系を使っている
以下のような否定系にはindexが効かない
- <>
- !=
- NOT IN
複合indexの順番を間違えている
col_1,clo_2,clo_3の順番にindexが貼られているとする
-- indexを利用していない
SELECT *
FROM SomeTable
WHERE col_2 = 30
AND clo_1 = 10
AND clo_3 = 30;
SELECT *
FROM SomeTable
WHERE col_1 = 10
AND clo_3 = 20;
SELECT *
FROM SomeTable
WHERE col_2 = 30
AND clo_3 = 30;
-- indexを利用している
SELECT *
FROM SomeTable
WHERE col_1 = 10
AND clo_2 = 20
AND clo_3 = 30;
SELECT *
FROM SomeTable
WHERE col_1 = 10
AND clo_2 = 20;
感想
EXISTSは知ってはいたもののどうゆう挙動するのかあまりわかっていないので使っていなかった。サブクエリをする上ではEXISTSを意識してみようと思う。
ソートには負荷がかかるのは知っていたが、GROUP BYなど結構よく使う。
INDEXについて今までINDEXついているものを検索に使おうと心がけていたが、順番や否定系には使えないことは学びだった。
業務でかなりのレコード数があるテーブルでSQLを書くときに、重くて取得できないことがよくある。こうした小さな工夫の組み合わせでパフォーマンス向上させられるといいなと思うので、また勉強してみようと思う。