【问题标题】:Laravel: is there a way to execute fast bulk update?Laravel:有没有办法执行快速批量更新?
【发布时间】:2021-07-16 12:01:49
【问题描述】:

我最近在mySQL中遇到了一种快速批量更新的方法:

缓慢的方式:

UPDATE `example` SET `name` = 'Mary', `age` = '20' WHERE id = 2;
UPDATE `example` SET `name` = 'Nancy', `age` = '30' WHERE id = 4;
UPDATE `example` SET `name` = 'Oliver', `age` = '40' WHERE id = 5;

快捷方式:

UPDATE `example` SET 
`name` = ELT(FIELD(id,2,4,5),'Mary','Nancy','Oliver') ,
`age` = ELT(FIELD(id,2,4,5),'20','30','40') 
WHERE id IN (2,4,5);

根据我的google搜索,fast方式在大规模上比slow方式快50倍,所以我想知道Laravel是否支持这种类型的批量更新,而无需执行自己生成的原始sql。

另外,如果有人熟悉mysql并且可以告诉我这是否真的那么快,如果有任何场景这种方法实际上更糟糕,我会非常优雅。

编辑(根据评论中的要求):

我当前的 Laravel 代码将像这样进行更新:

foreach ($modelList as $model) {
    $model->setConnection($connection);
    $model->save();
}

我想要批量更新的是

DB::connection($connection)->table($table)->bulkUpdate($models);

据我所知,目前 Laravel 已经支持批量插入,如下所示:

foreach ($models as $model) {
    $attributes = $model->getAttributes();
    $params[] = $attributes;
}

DB::connection($connection)->table($table)->insert($params);

这将生成一个包含多条记录的插入语句,而不是多个插入语句。

【问题讨论】:

  • 你能addthe Laravel code you already have回答你的问题吗?
  • @shaedrich 我已经添加了我想要的代码格式
  • 你为什么要$model->getAttributes()?如果您已经在模型中设置了修改后的值,您可以使用$model->save()。
  • 您可以使用此可能重复的 sql 并将其转换为您的查询生成器,stackoverflow.com/questions/3432/multiple-updates-in-mysql
  • @shaedrich 当我在循环中执行 model->save() 时,我将生成两个不同的插入 sql,而如果我执行 table()->insert(params),我将有一个插入 sql生成“值”之后的两行,这要快得多。

标签: mysql laravel sql-update bulkupdate


【解决方案1】:

如果没有解决方案,您仍然可以使用准备好的语句进行原始操作:

DB::update("
    UPDATE `example` SET 
        `name` = ELT(FIELD(id,2,4,5),?,?,?) ,
        `age` = ELT(FIELD(id,2,4,5),?,?,?) 
    WHERE id IN (?,?,?)
", [
    'Mary', 'Nancy', 'Oliver',
    '20', '30', '40',
    2, 4, 5
]);

从技术上讲,这也应该有效。还没查:

$sql = DB::table('users')->update([
  ['name' => DB::raw("ELT(FIELD(id,2,4,5),'Mary','Nancy','Oliver')")],
  ['age' => DB::raw("ELT(FIELD(id,2,4,5),'20','30','40')")]
])
->whereIn('id', [ 2, 4, 5 ]);

【讨论】:

  • 谢谢你的回答,实际上这是我准备的最坏的情况。缺点是代码看起来很难看,但如果框架不支持这个,恐怕我将不得不这样做。但是我不敢相信这样一个流行的框架不支持这种需求,特别是考虑到已经支持批量插入。
  • 给我几分钟,我正在检查一个替代方案。
  • 谢谢你的替代方法,看起来很聪明。我已投赞成票,稍后会尝试,如果可行,我会接受答案。
  • 根据this article,您可以在update() 中使用原始表达式,但您仍然必须在其中获取值。这就是问题所在。
  • 只要它在功能上工作,我认为生成原始部分不会是一个大问题。重要的部分是代码可读性,我认为只生成原始部分会非常结构化,不会使代码过于混乱。我明天回去工作时测试一下。
【解决方案2】:

另一种方法:

INSERT INTO t
    (name, age, id)
VALUES
    ('Mary', 20, 2),
    ('Nancy', 30, 4),
    ('Oliver', 40, 5)
ON DUPLICATE KEY UPDATE name = VALUES(name);

假设 id 已经在表中并且它有 PRIMARY KEY(id),那么就会有任何 INSERTs,只有 UPDATEs——这就是你想要的。

name = VALUES(name) 是一个虚拟空操作。在 MySQL 8.0 中需要更改为name = NEW.name。

【讨论】:

  • 感谢您的回答。这种方法的缺点是不会失败,但会在key不在表中时插入,这不符合我的具体项目目的。但是,我很感兴趣,是否可以通过这种方式使用 Laravel Query Builder 并且只编写最少量的原始 Sql。
【解决方案3】:

UPDATE student set roll='12',fee=fee-10 where roll='15'

将此示例用于您的代码。这是支持任何 mysql 平台的更简单、最快的方法。

【讨论】:

  • 这不是批量更新,它只更新一个条目
猜你喜欢
  • 2014-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-12
相关资源
最近更新 更多