LoginSignup
2
0

More than 1 year has passed since last update.

LaravelでLazy LoadingとEager Loadingの処理速度を比較してみた。

Last updated at Posted at 2022-09-30

はじめに

LazyLoadingEager Loadingってどれぐらい速度が変わるんだ?と思ったので比較してみます。

環境

M1 Mac

ProductName:	macOS
ProductVersion:	11.6
BuildVersion:	20G165

Docker for Mac

Docker version 20.10.12, build e91ed57

PHP, Laravel

$ php --version
PHP 8.0.23 (cli) (built: Sep 13 2022 11:09:24) ( NTS )
Copyright (c) The PHP Group
Zend Engine v4.0.23, Copyright (c) Zend Technologies

$ php artisan --version
Laravel Framework 9.31.0

テーブル

長くなっちゃうのでだいぶ端折ります。
migration, factory, seeder, modelをそれぞれそれっぽいところを書きます。

Migrations

// authorsテーブルのマイグレーション定義
public function up()
{
    Schema::create('authors', function (Blueprint $table) {
        $table->id();
        $table->string('name');
    });
}

// booksテーブルのマイグレーション定義
public function up()
{
    Schema::create('books', function (Blueprint $table) {
        $table->id();
        $table->integer('author_id', false, true)->references('id')
            ->on('authors')->onUpdate('CASCADE')->onDelete('CASCADE');
        $table->string('name');
    });
}

Fakers

// AuthorFactory
public function definition()
{
    return [
        'name' => $this->faker->name()
    ];
}

// BookFactory
public function definition()
{
    return [
        'author_id' => Author::factory(),
        'name' => $this->faker->sentence,
    ];
}

Seeders

// BookSeeder
public function run()
{
    \App\Models\Book::factory(10000)->create();
}

// DatabaseSeeder
public function run()
{
    $this->call([
        BookSeeder::class,
    ]);
}

Model

// BookModel リレーション
public function author(): HasOne
{
    return $this->hasOne(Author::class, 'id', 'author_id');
}

ターミナルでたーん!

$ php artisan migrate --seed

  INFO  Running migrations.

2022_09_28_054159_create_books_table ............................. 30ms DONE
2022_09_28_054234_create_author_table ............................ 27ms DONE

  INFO  Seeding database.

Database\Seeders\BookSeeder ........................................ RUNNING
Database\Seeders\BookSeeder ............................... 9,115.43 ms DONE

処理時間の計測

やっと準備完了しました。さっそく遊んで行きます。

Lazy Loading

api.php
// Lazy Loading
$time_start = microtime(true);
$books = Book::get();
foreach ($books as $book) {
    $book->author;
}
$time_end = microtime(true);
$lazy_time = $time_end - $time_start;
echo ('Lazy Loading : ' . $eager_time . " [sec]\n");

unset($books, $time_start, $time_start);

// Eager Loading
$time_start = microtime(true);
$books = Book::with('author')->get();
$time_end = microtime(true);
$eager_time = $time_end - $time_start;
echo ('Eager Loading : ' . $eager_time . " [sec]\n");
echo ($lazy_time / $eager_time . '倍');
$ curl localhost:200/api
Lazy Loading : 5.0409960746765 [sec]
Eager Loading : 0.16714096069336 [sec]
30.16014778044 倍

30倍も早いんですね。

いろいろ変えて試してみる

カラム数とかって影響するのか気になったのでauthorsテーブルに1カラム追加します。

ALTER TABLE `authors` ADD COLUMN `random_string` VARCHAR(255) DEFAULT 'test' AFTER `name`;

誤差レベルですね・・・むしろ速くなってる。

$ curl localhost:200/api
Lazy Loading : 5.0331110954285 [sec]
Eager Loading : 0.16527915000916 [sec]
30.452184048319 倍

indexはってみたらどうかしら。

CREATE UNIQUE INDEX `index_id` ON `authors` (`id`);
CREATE UNIQUE INDEX `index_id` ON `books` (`id`);

誤差ですねぇ。

Lazy Loading : 4.9837791919708 [sec]
Eager Loading : 0.17623591423035 [sec]
28.279021411361 倍

本の著者が複数人でもいいじゃないということで、一対多リレーションに変更してみます。
変更したファイルだけ書いてます。

Migrations

// booksテーブル
public function up()
{
    Schema::create('books', function (Blueprint $table) {
        $table->id();
        // $table->integer('author_id', false, true)->references('id')
        //    ->on('authors')->onUpdate('CASCADE')->onDelete('CASCADE');
        $table->string('name');
    });
}

// authorsテーブル
public function up()
{
    Schema::create('authors', function (Blueprint $table) {
        $table->id();
        $table->integer('book_id', false, true)->references('id')
            ->on('books')->onUpdate('CASCADE')->onDelete('CASCADE');
        $table->string('name');
    });
}
Book.php
public function authors(): HasMany
{
    return $this->hasMany(Author::class, 'book_id', 'id');
}
BookSeeder.php
public function run()
{
    $faker = \Faker\Factory::create();

    \App\Models\Book::factory(10000)->create()->each(function ($book) use ($faker) {
        \App\Models\Author::factory(2)->create([
            'book_id' => $book->id,
            'name' => $faker->name(),
        ]);
    });
}

たーん

$ php artisan migrate:refresh

  INFO  Rolling back migrations.

  2022_09_28_054234_create_author_table .................................................................................................. 20ms DONE
  2022_09_28_054159_create_books_table ................................................................................................... 10ms DONE
  2019_12_14_000001_create_personal_access_tokens_table ................................................................................... 6ms DONE

   INFO  Running migrations.

  2019_12_14_000001_create_personal_access_tokens_table ................................................................................. 105ms DONE
  2022_09_28_054159_create_books_table ................................................................................................... 31ms DONE
  2022_09_28_054234_create_author_table .................................................................................................. 30ms DONE

$ php artisan db:seed

   INFO  Seeding database.

  Database\Seeders\BookSeeder .............................................................................................................. RUNNING
  Database\Seeders\BookSeeder .................................................................................................... 13,367.11 ms DONE

さらにたーん

$ curl localhost:200/api/
Lazy Loading : 130.49195289612 [sec]
Eager Loading : 0.20387506484985 [sec]
640.05842495854 倍

....ふぁっ!? Lazy Loadingの方は約26倍も経過時間が増えているのに対してEager Loading0.03秒しか増えていらっしゃらないので640倍も速度差がでてしまいました。圧倒的じゃないか我が軍は・・・(にわか)

検証?おわり

ちゃんとEager Loadingを使わないとえらい目に合うことがよく分かりました。

参考

LaravelのEager LoadingLazy Laodingについて

Eager Loading, LazyLoadingのSQL発行回数の確認方法

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