如果一个表中有1W条数据的表A,需要转储到表B中,怎么么样会更快呢?这个问题在我这篇文章的末尾已经有了解答 -> mysql存储引擎的概念
如果是分批次转储的话,每次是越多越好呢?还是合理更好呢?为了满足好奇心,我做了以下这个小实验记录一下?
两个表 test1我插入1W条数据 通过
insert into test2 select id from test where id between {$min} and {$max}
语句查询插入
代码 中的 max min 我随机调的 根据后面的测试结果为主
for ($i=1;$i<10;$i++) {
$max = $i * 1000;
$min = $max - 1000+1;
$sql = "insert into test2 select id from test1 where id between {$min} and {$max}";
$query = \think\facade\Db::query($sql);
// $data = [
// 'id' => $i
// ];
// \think\facade\Db::name('test')->insert($data);
}
$end_time = microtime(true);
$time = $end_time-$start_time;
echo $time;
分10次插入 每次 1000 条 : 执行时间 0.061244964599609
分05次插入 每次 2000条 : 执行时间 0.037288904190063
分02次插入 每次 5000条 : 执行时间 0.017976045608521
可能是数据量不够大,现在我插入一百万条 ,再试一下
for循环插入100万条数据.程序以及崩溃掉了
数据量太大了,好吧 尝试一下 sql语句拼接
此路也是不通,虽然效率还可以,但是服务器的内存不够用,而且sql语句的长度是有限制的!
尝试使用事务!
耗时12分钟
采用消息队列
// 入队逻辑
$queueFile = '\app\controller\job\Index';
$queueName = 'insertTest';
for ($i=1;$i<1000;$i++) {
$params = [
'id' => $i,
'name' => $i,
];
$pushTask = \think\facade\Queue::push(\app\controller\job\Index::class,$params,$queueName);
}
// 消费逻辑
public function fire(Job $job,$data)
{
$consumer = $this->consumer($data);
if ($consumer) {
$job->delete();
return;
} else {
// 否则 检查执行次数 如果已经重试3次
if ($job->attempts() > 3){
// 通过这个方法可以检查这个任务已经重试了几次了
// 删除任务 执行失败
print("<warn>Hello Job has been retried more than 3 times!"."</warn>\n");
$job->delete();
return;
}
}
}
public function consumer($data)
{
$data['time'] = time();
$insert_line = Db::name('person')->insert($data);
if ($insert_line) {
return true;
}
return false;
}
立刻返回了结果,但是程序仍然在一条一条的去插入;
在数据里做插入操作的时候,整体时间的分配是这样的:
链接耗时 (30%)
发送query到服务器 (20%)
解析query (20%)
插入操作 (10% * 词条数目)
插入index (10% * Index的数目)
关闭链接 (10%)
所以 这中方案对数据库的消耗反而更大!