ORM は、データベースのテーブルやレコードを、プログラム側のクラスやオブジェクトとして扱えるようにする仕組みです。Laravel の Eloquent や Django の ORM が代表例です。
// SQL を書かずに、モデルとして扱える
$user = User::find(123);
$user->name = 'yamada';
$user->save();
一覧、登録、更新、削除が中心のアプリでは、書く量が目に見えて減ります。
いちばん多い事故は N+1
ORM で起きる問題の大半がこれです。一覧を取り、その1件ごとに関連を参照すると、件数に比例して問い合わせが増えます。
// 投稿を100件取る → ここで1回
$posts = Post::all();
foreach ($posts as $post) {
// 1件ごとに著者を引く → ここで100回
echo $post->author->name;
}
合計101回です。コードの見た目には回数が出てこないので、書いているときは気づけません。件数が少ない開発環境では速く、本番でデータが増えてから遅くなります。
直し方は、関連をまとめて先に読み込むことです。
$posts = Post::with('author')->get(); // 2回で済む
同じ形の問題は GraphQL でも起きます。1件ずつ引く形になっていないかは、仕組みを問わず疑う価値があります。
発行された SQL を見る
ORM を使ううえで、いちばん役に立つ習慣がこれです。何が発行されているかを見れば、上の N+1 も一目で分かります。
- Laravel:
DB::enableQueryLog()を有効にしてDB::getQueryLog()で確認する。開発時はデバッグツールで一覧表示する方が早い - Django:
django.db.connection.queriesを見る
⚠️ 見るべきは SQL の中身だけでなく「回数」です。 1本ずつは軽くても、100回飛んでいれば遅くなります。
ORM で書かない方がよい場面
ORM は万能ではありません。次のような場面では、素直に SQL を書いた方が読みやすく速くなります。
- 集計が複雑なとき(複数のグループ化、ウィンドウ関数を使う集計)
- 大量の更新を一括で行うとき(1件ずつオブジェクトにすると、件数分のメモリと時間を使う)
- 性能のために書き方を細かく制御したいとき
「ORM を使うと決めたら全部 ORM」である必要はありません。大部分は ORM、重い部分だけ SQL、という使い分けが実務では普通です。
よくある誤解
「ORM を使えば SQL を知らなくていい」は正しくありません。書く機会は減りますが、遅い・件数が合わないといった問題に向き合うときは、結局 SQL を読むことになります。ORM が肩代わりしているのは記述であって、データベースの動きそのものではありません。