Help us understand the problem. What is going on with this article?

Laravel でむやみに Model all() を使うとパフォーマンスが悪くなる

はじめに

(サンプルのバージョンは 5.5 で書いてます)

Laravelって便利。リレーションだって簡単に貼れます。
しかし、書き方によって予期しない挙動したので備忘録として残します。

実際にやってみた

まずサンプルとして、ユーザ情報を扱うテーブルと、トレーニング情報を扱うテーブルを用意。

CREATE TABLE `users` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `name` varchar(64) NOT NULL COMMENT '名前',
  `deleted_at` datetime DEFAULT NULL COMMENT '削除日時',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='ユーザ';

CREATE TABLE `trainings` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
  `trained_user_id` int(10) unsigned NOT NULL COMMENT 'トレーニング者',
  `summary` varchar(255) NOT NULL COMMENT '概要',
  `deleted_at` datetime DEFAULT NULL COMMENT '削除日時',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='トレーニング';

トレーニング情報と一緒に、トレーニング者のユーザ名を取得したいとき、
Modelクラスでこのように関数を設置し、belongsToでリレーションを貼っておくと、
Training情報を取得した時にも trained_user関数 を呼び出しただけで users 情報を取得できます。

Training.php
use Illuminate\Database\Eloquent\Model;

/**
 * Class Training
 */
class Training extends Model
{
    public function trained_user()
    {
        return $this->belongsTo(User::class);
    }
}
$trainings = Training::all();
$trainings[0]->trained_user->name; // トレーニング者の名前が取れる

でも、やったね!と思ってクエリログを見ると愕然します...

select * from `trainings` where `trainings`.`deleted_at` is null
select * from `users` where `users`.`id` = '1' and `users`.`deleted_at` is null limit 1
select * from `users` where `users`.`id` = '2' and `users`.`deleted_at` is null limit 1
select * from `users` where `users`.`id` = '3' and `users`.`deleted_at` is null limit 1

みてください、・・・ユーザ分毎回SQL投げてる;;;;
めっちゃパフォーマンス悪い;;;;

反省して書き直し。

$trainings = Training::with(['trained_user'])->get(); // trained_user を設定する
$trainings[0]->trained_user->name; // 同様にトレーニング者の名前が取れる

クエリログは・・・

select * from `trainings` where `trainings`.`deleted_at` is null
select * from `users` where `users`.`id` in ('1', '2', '3') and `users`.`deleted_at` is null

期待どおりの結果になりました!
というわけで、リレーション貼ってる時は気をつけましょう〜

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした