[英]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.