我尝试使用大量点击来测试数据库以测试我的仪表板指标显示。所以我想生成25k命中,并将它们与数据库中的随机Post
相关联,以便数据保持一致。
我最初尝试在Post
课程中抓取一个随机HitFactory
,但这真的非常非常慢(就像生成数千次点击的时间一样)。然后我将随机部分移动到播种器类中,并且只调用一次以最小化DB命中,认为这会大大加快它的速度。但它没有 - 创建一个Hit
对象仍需要至少5-10秒。
我不确定这是怎么可能的 - 我是否缺少优化?请注意,我不能只生成1到x之间的随机int,并将其用作链接Post
,因为我使用了posts
表的UUID样式ID。
这是需要很长时间才能运行的播种机:
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];
答案 0 :(得分:3)
只是发布此内容,以防将来对任何人有帮助。我遇到了一个插入速度极慢的类似问题。如果使用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())。希望它会有所帮助,但我不确定100%。
答案 1 :(得分:0)
首先尝试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
循环中的帖子。
答案 2 :(得分:0)
$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();