繁体   English   中英

Laravel 5.5播种机真的很慢

[英]Laravel 5.5 seeder really slow

我正在尝试使用大量命中来测试数据库以测试我的仪表板指标显示。 所以我想生成25k命中,并将它们与数据库中的随机Post相关联,以便数据保持一致。

我最初试图在HitFactory类中抓取一个随机的Post ,但这真的非常非常慢(比如产生数千次点击的时间)。 然后我将随机部分移动到播种器类中,并且只调用一次以最小化DB命中,认为这会大大加快它的速度。 但它没有 - 创建一个Hit对象至少需要5-10秒。

我不确定这是怎么可能的 - 我是否缺少优化? 请注意,我不能只生成1 - x之间的随机int并将其用作链接Post ,因为我正在使用UUID样式ID作为posts表。

这是需要很长时间才能运行的播种机:

use Illuminate\Database\Seeder;

class HitsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {

        $posts = App\Post::all();

        $i = 0;

        while ($i <= 25000) {
            $post = $posts->random();
            factory(App\Hit::class)->create(
                [
                    'post_key' => $post->post_key,
                    'subject_code' => $post->subject_code,
                    'subject_id' => $post->subject_id,
                ]
            );
            $i++;
        }
    }
}

编辑:我还尝试在HitsTableSeeder生成1-500之间的随机int,并使用它作为$posts集合的索引来完全消除random()调用。 它仍然比我想象的要慢。

    while ($i <= 25000) {
        $t = rand(0, 500);
        $post = $posts[$t];

只是张贴这个,以防它可以帮助任何人在未来。 我遇到了类似的问题,插入速度极慢。 如果您使用的是MySQL,请尝试使用数据库事务。 在您的情况下,在while循环之前手动启动事务并在之后提交事务。 显然,如果您不手动启动并为整个组(或者如果您愿意,则为块)提交事务,则MySQL引擎将单独提交每个插入(增加大插入时引人注目的开销)。 这样做后我看到了巨大的性能提升。 不仅仅是分块,在我的情况下实际上对性能没有帮助。 像这样的东西:

use Illuminate\Database\Seeder;

class HitsTableSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {

        $posts = App\Post::all();

        $i = 0;

        DB::beginTransaction();

        while ($i <= 25000) {
            $post = $posts->random();
            factory(App\Hit::class)->create(
                [
                    'post_key' => $post->post_key,
                    'subject_code' => $post->subject_code,
                    'subject_id' => $post->subject_id,
                ]
            );
        }

        DB::commit();
    }
}

编辑 :只是一个注释,我实际上还没有尝试过工厂,只有常规插入(例如与Model :: create())。 希望它有所帮助,但我不是百分百肯定。

首先尝试make Hit实例,然后将其分块为$posts->count()的大小:

$posts = App\Post::all();
$n = $posts->toArray();
$m = 25000;
$c = $posts->count();

factory(App\Hit::class, $m)->make()->chunk($c, function ($hits) use ($n) {
    foreach ($hits as $i => $hit) {
        $hit->fill([
            'post_key' => $n[$i]['post_key'],
            'subject_code' => $n[$i]['subject_code'],
            'subject_id' => $n[$i]['subject_id']
        ]);
        $hit->save();
    }
});

这会让你将Hit记录分散到Posts 如果你想要一个更随机的权重,你可以使用array_random来调整内部$hits循环中的帖子。

$posts = App\Post::orderBy('id')->take(25000)->chunk(250, function ($posts) {
    foreach ($posts as $post) {
        //
    }
});

只是为了确保你不是一次检索所有记录并将它们分成250个每个查询来节省内存。 但是尝试使用$faker在工厂目录中创建此工厂。

<?php

use Faker\Generator as Faker;

$factory->define(App\Post::class, function (Faker $faker) {
    return [
        'post_key' => $faker->name,
        'subject_code' => $faker->address,
        'subject_id' => $faker->numberBetween(1,25000)/* or either make it auto increment or loop on a counter */,
    ];
});

现在在播种器运行方法内部只需调用:

factory(App\Post::class, 25000)->create();

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM