1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

SQLを組むとき気をつけること

Last updated at Posted at 2023-08-03

基本

SQLは2種類に分けられる。
検索か、検索でないかだ。

パフォーマンスについて気にするのは、ほぼ検索のときだけ。
数百件のデータから検索するときには問題にならないSQLも、数万、数十万とデータ量が増えると重すぎて動かなくなる。

データ量が増えても、検索の負荷はそれほど増えないSQLにすることが必要。

そのためには、インデックスを使うことがポイントとなる。

インデックスというのは、図書館の分類法のような仕組みで、データを木構造に順番どおりに並べて、データの位置と検索速度が比例しないようにできる。

50番目だろうが、5千兆番目だろうが、同じくらいの速度で検索できるようになる。
(もちろん、全体のデータ量が増えれば検索時間も増える。対数的に。でも、B+木の構造であれば枝の深さが等しい、平衡木なので、何番目かには比例しない)

気をつけること

group by, sort by

これらをインデックスの貼られてないカラムに対して行うと、重くなる原因になる。

JOIN

JOINの結合条件にインデックスが貼られていないカラムを使用すると、重くなる原因になる。
また、一般的に、対象のレコード数が小さいテーブルを先に結合するほうが、検索対象となるレコード数を節約できる。

後方一致検索

後方一致ならインデックスが使えるが、前方一致だと使えないので注意。

関数を使用する

検索値のほうに関数を使用するならいいが、カラムのほうに使用してしまうとインデックスが効かない。

UNION

unionはソートして重複行を削除してくれる。
その分パフォーマンスが悪いことがある。
重複行を取得してもよければ、union allを使用しよう。

N+1問題

関連テーブルからデータを取得するようなときに、SQLがN+1回発行される有名な問題。
1回分は主テーブルからN個のリストを取得するとき。
N回分は、関連テーブルのデータを、主テーブルのレコード数分繰り返して取得するとき。
Joinで一度に取得することが望ましい。
(とはいえ場合によっては適宜もってきたほうがいいこともあるし、ORMではLazy Loadといってあえて一度に持って来ない設定もできることが多い。)

サブクエリー

サブクエリーを使う場合は、JOINで使用することが多いと思う。
その場合、できるだけサブクエリー内で取得される件数を減らしたほうがいい。
例)

SELECT * FROM A INNER JOIN (SELECT id,created_at FROM B) as sub ON A.b_id=sub.id WHERE b.created_at > '2022-10-10'

よりも

SELECT * FROM A INNER JOIN (SELECT id FROM B WHERE b.created_at > '2022-10-10') as sub ON A.b_id=sub.id WHERE b.created_at > '2022-10-10'

のほうがいい。

まとめ

インデックスには、メモリーを使うとか、登録処理のたびに作り直すオーバヘッドが生じるなど、デメリットもあるので、要らないなら作らなくていい。
また、DBがどのインデックスを使用するかは、統計的に決まったりもするので、パフォーマンスは理論上だけでは決まらない。
実際に測ってみたり、実行計画をみたりするのが大事。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?