2
0

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.

LaravelのEloquentが実際にどんなクエリを発行しているか調べてみた

Last updated at Posted at 2022-08-09

概要

Laravel組み込みのORMであるEloquentが実際どんなクエリを発行しているのか、理解を深めるために調べてみました。
今回はリレーションに関わる基本的な部分を記載しています。

環境

Laravel v6.20.26

ER図

er.png

モデルへ定義したリレーション

Country.php
    public function posts()
    {
        return $this->hasManyThrough('App\Post', 'App\User');
    }
User.php
  public function posts()
  {
    return $this->hasMany('App\Post');
  }

  public function favorite_posts()
  {
    return $this->belongsToMany('App\Post', 'favorite', 'user_id', 'post_id');
  }
Post.php
    public function user()
    {
        return $this->belongsTo('App\User');
    }

    public function favorite_users()
    {
      return $this->belongsToMany('App\User', 'favorite', 'post_id', 'user_id');
    }

クエリ一覧

基本的に各テーブルはid=1のデータを利用しています。

hasMany

$user->posts;
select * from `posts` where `posts`.`user_id` = 1 and `posts`.`user_id` is not null

belongsTo

$post->user;
select * from `users` where `users`.`id` = 1 limit 1

hasManyThrough

$country->posts;
select
    `posts`.*,
    `users`.`country_id` as `laravel_through_key`
from
    `posts`
    inner join
        `users`
    on  `users`.`id` = `posts`.`user_id`
where
    `users`.`country_id` = 1

belongsToMany

$user->favorite_posts;
select
    `posts`.*,
    `favorite`.`user_id` as `pivot_user_id`,
    `favorite`.`post_id` as `pivot_post_id`
from
    `posts`
    inner join
        `favorite`
    on  `posts`.`id` = `favorite`.`post_id`
where
    `favorite`.`user_id` = 1

attach/detach/sync

syncがattachとdetachの組み合わせなのでそちらだけ紹介します。
事前にpost_id=1,2がattachされています。事前にユーザーに紐づくfavoriteを全て取得し、内部でレコードの有無を判断して作成・削除をしています。

$user->favorite_posts()->sync([1,3]);
select * from `favorite` where `favorite`.`user_id` = 1;
delete from `favorite` where `favorite`.`user_id` = 1 and `favorite`.`post_id` in (2);
insert into `favorite` (`post_id`, `user_id`) values (3, 1);

with(Eager Load)

User::with(['posts'])->get();
select * from `users`;
select * from `posts` where `posts`.`user_id` in (1, 2);

条件に合致するuserを全て取得した後、対応するposを全て取得し内部で紐付けています。
データベースへの問い合わせが一度で済むので、N+1問題への対処として利用されます。

まとめ

シンプルなリレーションに関しては予想通りだと思いますが、syncなどはクエリでの処理とアプリでの処理がどのように分離されているのかがわからなかったので勉強になりました。
備忘録代わりに今後もまとめていきたいです。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?