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?

Laravel Eloquent ORMの効率的なデータ取得とスマートな書き方

Posted at

はじめに

LaravelのEloquent ORMは、シンプルで直感的に使える強力なツールですが、使い方次第ではパフォーマンスが最適化されない場合があります。例えば、不用意にJOINを使用してクエリが重くなる、繰り返し使うコードが冗長になってしまうといった問題です。今回は、これら欠点の解決策を紹介し、効率的かつパフォーマンスを向上させる方法を解説します。

1. サブクエリを活用した効率的なデータ取得

従来の書き方

大量のデータがある場合、JOIN によりパフォーマンスが悪化する場合がある。

// JOINを使用したデータ取得
$users = User::with('orders')->get();

解決策

サブクエリを使用してパフォーマンス向上。

$users = User::addSelect(['latest_order' => Order::select('id')
    ->whereColumn('user_id', 'users.id')
    ->latest()
    ->limit(1)
])->get();

2. 動的スコープでコードをすっきりさせる

従来の書き方

似たようなクエリがあった時に記述が重複して冗長、保守性からもあまり望ましくない。

$activeUsers = User::where('status', 'active')->get();
$inactiveUsers = User::where('status', 'inactive')->get();

解決策

Model内で動的スコープを活用し呼び出すことで、再利用性を高める。

class User extends Model {
    public function scopeActive($query) {
        return $query->where('status', 'active');
    }
    public function scopeInactive($query) {
        return $query->where('status', 'inactive');
    }
}

// 使用例
$activeUsers = User::active()->get();
$inactiveUsers = User::inactive()->get();

3. firstOrCreate / updateOrCreate を活用

従来の書き方

対象のuserが存在するかどうかで分岐するので少し冗長。

$user = User::where('email', 'example@example.com')->first();
if ($user) {
    $user->update(['name' => 'John Doe']);
} else {
    User::create(['email' => 'example@example.com', 'name' => 'John Doe']);
}

解決策

firstOrCreate , updateOrCreate を使用。

// firstOrCreate を使用
$user = User::firstOrCreate(
    ['email' => 'example@example.com'],
    ['name' => 'John Doe', 'status' => 'active']
);

// updateOrCreate を使用
$order = Order::updateOrCreate(
    ['user_id' => 1, 'product_id' => 10],
    ['quantity' => 5, 'status' => 'pending']
);

4. 少しマイナーなメソッドを活用する

whereExists() を使ったサブクエリの最適化

従来の書き方

whereHas を利用すると内部で別のクエリが実行されるため、場合によってはパフォーマンスに影響がでる可能性がある。

$users = User::whereHas('orders', function ($query) {
    $query->where('status', 'completed');
})->get();

解決策

サブクエリ whereExists を活用して冗長な処理を簡潔に。

$users = User::whereExists(function ($query) {
    $query->select(DB::raw(1))
          ->from('orders')
          ->whereColumn('orders.user_id', 'users.id')
          ->where('orders.status', 'completed');
})->get();

5. クエリビルダーとEloquentの融合

従来の書き方

DBファサード(DB::table)を使用する場合、Eloquentモデルが持つメリット(リレーションの扱いや保守性)が失われることがある。また、パラメータバインディングが正しく行われていないとSQLインジェクションなどのリスクが生じる可能性がある。

$users = DB::table('users')
    ->whereRaw("DATE(created_at) = ?", [now()->toDateString()])
    ->get();

新しい方法

Eloquentを利用することで、パラメータバインディングが自動的に適用されるため、モデルレベルのセキュリティ対策やその他の便利な機能が得られる。

$users = User::whereRaw("DATE(created_at) = ?", [now()->toDateString()])->get();

まとめ

  • サブクエリを活用して不要なJOINを削減
  • 動的スコープを利用してコードの再利用性を向上
  • firstOrCreate()updateOrCreate() を活用して冗長な処理を簡潔に
  • whereExists() を利用してサブクエリを最適化

採用拡大中!

アシストエンジニアリングでは一緒に働くフロントエンド、バックエンドのエンジニア仲間を募集しています!
少しでも興味ある方は、カジュアル面談からでもぜひお気軽にお話ししましょう!

お問い合わせはこちらから↓
https://official.assisteng.co.jp/contact/

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?