laravel+mysql每秒2000的插入的最佳方案是什么呢?

1. 运行环境

1). 当前使用的 Laravel 版本?

2). 当前使用的 php/php-fpm 版本?

PHP 版本:php8.0

php-fpm 版本:

3). 当前系统

4). 业务环境

5). 相关软件版本

mysql5.7

2. 问题描述?

进销存系统,数据是从excel文件导入的,大概是要求1分钟12
w的数据,插入逻辑不复杂,只是在插入之前查询对应商品的库存。有库存就插入。

3. 您期望得到的结果?

每秒mysql2000的插入量
//: <> (能截图就截图。)

4. 您实际得到的结果?

《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 33

队列异步批量插入吧

1年前 评论

1,excel 读取的数据,先存缓存 2,缓存中的数据,走kafka队列进行存储到mysql中

1年前 评论
Xiaoxiaoww (楼主) 1年前

字符串拼接插入吧

1年前 评论
Xiaoxiaoww (楼主) 1年前
陈先生
  1. 读取 Excel 文件内的数据,拼接成 商品id 为key 的数组。
  2. 过滤掉库存为空的数据
  3. 直接丢进异步消息队列执行插入,同时开多个进程去跑。

注意事项: 因为队列中仅做插入操作,如果在推入队列和执行队列中发生了库存清空的场景,需要自行做处理。

1年前 评论
Xiaoxiaoww (楼主) 1年前
图米 1年前
Geekc 1年前
Xiaoxiaoww (楼主) 1年前
Geekc 1年前
梦想星辰大海

你这个需求本质上是如何快速计算出待插入数据。 至于mysql的插入速度,反而是最简单的,用批量插入就可以。 快速计算出待插入数据的逻辑里面,如果计算过程有io,就用协程,如果纯cpu计算,那就多开线、进程。

1年前 评论
Xiaoxiaoww (楼主) 1年前
梦想星辰大海 (作者) 1年前
Xiaoxiaoww (楼主) 1年前
梦想星辰大海 (作者) 1年前
  1. 使用多线程或多进程:可以将插入操作分配到多个线程或进程中,以提高插入速度。这需要您在应用程序中实现多线程或多进程的代码逻辑,以确保线程/进程之间的同步和协作。

  2. 批量插入:可以使用 Laravel 提供的批量插入功能,将多个记录一次性插入到数据库中。这可以显著降低每个插入操作的开销,并提高插入速度。例如,使用 Eloquent ORM 提供的 insert 方法,可以将一个包含多个记录的数组一次性插入到数据库中,而不是使用循环插入单个记录。

  3. 还可以使用 Eloquent ORM 提供的 insert 批量插入方法并使用laravel 8或以上的任务批处理

1年前 评论
Xiaoxiaoww (楼主) 1年前
sanders

写入速度往往跟数据库服务器配置有关,但应该先从代码逻辑上进行优化,对数据进行分组加载到缓冲区,再分批写入:

class BatchImport
{
    public const BUFFER_SIZE = 1000;

    protected $file;
    protected $buffer = [];

    public function __construct()
    {
    }
    public function handle($file)
    {
        $this->file = $file;
        \Illuminate\Support\Facades\DB::transaction(function () {
            $this->provider();
        });
    }
    public function provider(): void
    {
        fastexcel()->import($this->file, fn ($line) =>
            $this->validate($line) && $this->import($line)
        );
    }

    protected function validate(array $line): bool
    {
        // TODO: 校验逻辑
        return true;
    }

    protected function import(array $line): array
    {
        if (count($this->buffer) >= self::BUFFER_SIZE) {
            $this->save();
            $this->buffer = [];
        }

        return $this->buffer[] = $this->transform($line);
    }

    protected function transform(array $line): array
    {
        return [
            // TODO: 字段值映射列的转换关系
        ];
    }

    protected function save(): void
    {
        Trade::insert($this->buffer);
        // TODO: 如果需要触发事件,可以在这里触发
    }
}

这里使用到事务批量写入来保证批次完整性,如果不需要可以移除事务来提高效率。

数据库方面可以采用多主库的方式进行连接,当然这样成本就提高了。

1年前 评论

我个人想法啊,如果逻辑不复杂,只有校验库存且库存当前不会实时变动的话,可以先全插在临时表,后续再delete :joy:

1年前 评论
Xiaoxiaoww (楼主) 1年前

如果是单纯解决插入的问题。可以考虑屏蔽索引。然后待所有数据插入后,再次开启索引。但是如何屏蔽索引,我就没啥印象了。你可以尝试下不同方案。

1年前 评论
  • 准备个临时表 temp_excel 格式跟要插入的目标表格式一致。
  • 读出 excel 内容,整理成 laravel 的批量插入格式的数据。并无脑批量插入
  • 使用 insert into 目标表 select temp_excel.字段1,temp_excel.字段2... from temp_excel left join 库存表 on temp_excel.货品ID = 库存表.货品ID where 库存表.库存 > 0 批量更新到目标表
  • 使用 truncate table temp_excel 清空临时表

那些使用队列的,你只是能快速返回看起来象是插入了,但实际上并没有,如果后续需要依赖插入的数据做其他处理,就可能发生找不到数据的麻烦。异步同时带来了错误处理上的麻烦。 简单粗暴的方案也许更好用。

1年前 评论
阿凡 1年前
Xiaoxiaoww (楼主) 1年前
qufo (作者) 1年前
Xiaoxiaoww (楼主) 1年前
qufo (作者) 1年前

1、你在意服务执行性能的话,可以先将数据记录到消息队列中,真实的处理流程异步处理。后台开几个常驻内存的cli进程,并行来完成存储数据库逻辑的操作。redis也是可以的,内存操作写入性能更好。不过就怕数据体量大了,redis数据容易丢。 2、可以调研存储的MongoDB中,对于字段不固定的数据,文档数据库的存储更加友好。扩展/并发较MySQL更好些。

1年前 评论
Xiaoxiaoww (楼主) 1年前

业务方便再讲讲吗,excel的数据是什么数据?(因为你这个需求有点奇怪),是商品名,库存数量这样吗,还有什么其他信息?
如果都是已有商品,那么就得一个一个商品处理(更新库存),也就是批量更新数据的问题,和插入数据没关系

1年前 评论

大致思路:批量读取数据2000,通过内存处理(一次查出所有有内存商品id,当前2000数据商品id,利用数组交并集运算),运算得出数据,然后更新数据又有两种方式,一种是能处理好数据加库存,批量更新(一次IO操作);另一种循环更新单条商品库存(多次IO操作);

1年前 评论

多线程,或者批量插入

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!