概述

在我们的平常业务中,经常需要批量更新数据,例如:现阶段需要更新 1000 个包裹的上网时间,每个包裹的上网时间是不一样的,假如我们一个一个包裹更新,则需要与数据库进行 1000 次的交互,很大的消耗数据库的性能,并且更新的速度也很慢,因此,我们通常需要进行批量更新数据。

数据生成

首先,我们需要生成一批测试数据,方便对批量更新进行测试。

创建数据表

CREATE TABLE users
(
id SERIAL PRIMARY KEY,
username VARCHAR(255) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
status VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by VARCHAR(255) DEFAULT 'system'
);

批量生成数据

INSERT INTO
users (username, email, password, status)
SELECT
SUBSTR(MD5(RANDOM()::TEXT), 10),
SUBSTR(MD5(RANDOM()::TEXT), 10) || '@qq.com',
MD5(RANDOM()::TEXT),
get_split_str('在职,离职')
FROM
GENERATE_SERIES(1, 10000);

生成数据的相关函数:PGSQL 快速生成数据函数

生成的数据

方案

临时表

将每次生成的数据插入至 PGSQL 的临时表,然后使用 UPDATE table FROM tmp_table 方式进行数据更新。

注意:假如此条 SQL 需要大量的执行,则不推荐此种方案,此种方案将会导致pg_attribute 表发生数据膨胀,而这张表又属于系统表,执行 VAUNCAM 的时候将会锁库,当数据膨胀后,VAUNCAM pg_attribute 将消耗大量的数据库性能,因此,当批量更新频率过大的时候,不推荐使用。

创建临时表

create TEMP table  "users_temp"  AS SELECT * FROM "users" WHERE 1=2;

将待更新的数据插入至临时表

INSERT INTO
users_temp(id, username, password, email, status, created_at, created_by)
SELECT
id, username, password, email, status, created_at, created_by
FROM
users
WHERE
id < 500
;

更新临时表的数据

UPDATE users_temp SET status = '在职';

批量更新

UPDATE users SET status = tmp.status FROM users_temp tmp WHERE users.id = tmp.id;

插入更新

插入更新主要是使用插入数据时, ID 主键冲突,利用ON CONFLICT(id) DO UPDTAE 特性,当 ID 重复时,数据库会自动执行更新语句。

下面是具体的 SQL

INSERT INTO users VALUES
(12, '152c336aa714f12a45608ed7', '87d166ef4357382a89709d243bf2f1bd', '1bd4c564afa1e5fee1f0f411@qq.com', '开心', '2024-02-23 16:33:22.133835', 'system'),
(13, '182eeda111284cbd39094ce0', 'e9f658d777fb7c83449166a430538ee2', '13675703c00f1040d762bef8@qq.com', '开心', '2024-02-23 16:33:22.133835', 'system'),
(14, '1d4ef943f76346625bbad9c6', '01a03911bc1039b68768dc62f55cae1d', '1a44dca3c9b6ca5329bbc415@qq.com', '开心', '2024-02-23 16:33:22.133835', 'system'),
(15, '1028f917f9fc53191564ce17', '031f3b53d6ce9eadbb2a15a69a4c223b', '19404aa589c9db19ee07ab75@qq.com', '开心', '2024-02-23 16:33:22.133835', 'system'),
(16, '164115c6e526c50ca41b7eba', '2165358e24236ce26b919cea7d0d1d86', '12aa7e3c1a23827b3e07d129@qq.com', '开心', '2024-02-23 16:33:22.133835', 'system')
ON CONFLICT(id)
DO UPDATE SET
id = excluded.id,
username = excluded.username,
password = excluded.password,
email = excluded.email,
status = excluded.status,
created_at = excluded.created_at,
created_by = excluded.created_by
;

上面示例中,当主键冲突的时候,自动更新部分字段

子表

将待更新的数据放入 SQL 子表中,使用子表替换上面的临时表,已达到 UPDATE table FROM 子表 效果,这种方案相对于临时表方案,不会创建新表,不会造成数据膨胀问题

下面是示例的 SQL

UPDATE users
SET
id = temp.id,
username = temp.username,
password = temp.password,
email = temp.email,
status = temp.status,
created_at = temp.created_at,
created_by = temp.created_by
FROM
(VALUES
(12, '52c336aa714f12a45608ed7', '87d166ef4357382a89709d243bf2f1bd', '1bd4c564afa1e5fee1f0f411@qq.com', '快乐', '2024-02-23 16:33:22.133835'::TIMESTAMP, 'system'),
(13, '82eeda111284cbd39094ce0', 'e9f658d777fb7c83449166a430538ee2', '13675703c00f1040d762bef8@qq.com', '快乐', '2024-02-23 16:33:22.133835'::TIMESTAMP, 'system'),
(14, 'd4ef943f76346625bbad9c6', '01a03911bc1039b68768dc62f55cae1d', '1a44dca3c9b6ca5329bbc415@qq.com', '快乐', '2024-02-23 16:33:22.133835'::TIMESTAMP, 'system'),
(15, '028f917f9fc53191564ce17', '031f3b53d6ce9eadbb2a15a69a4c223b', '19404aa589c9db19ee07ab75@qq.com', '快乐', '2024-02-23 16:33:22.133835'::TIMESTAMP, 'system'),
(16, '64115c6e526c50ca41b7eba', '2165358e24236ce26b919cea7d0d1d86', '12aa7e3c1a23827b3e07d129@qq.com', '快乐', '2024-02-23 16:33:22.133835'::TIMESTAMP, 'system'))
AS temp(id, username, password, email, status, created_at, created_by)
WHERE
users.id = temp.id
;

实体表

这种方案使用实体表替换临时表,每次 SQL 执行钱,执行 TRUNCAT TABLE 表名, 用来达到清空表数据的作用。

创建临时表

CREATE TABLE users_tmp AS SELECT * FROM "users" WHERE 1=2;

待更新数据插入临时表

INSERT INTO
users_tmp(id, username, password, email, status, created_at, created_by)
SELECT
id, username, password, email, status, created_at, created_by
FROM
users
WHERE
id < 500
;

更新临时表中的数据

UPDATE users_tmp SET status = '在职';

批量更新数据

UPDATE users SET status = tmp.status FROM users_tmp tmp WHERE users.id = tmp.id;

清空表数据

TRUNCATE TABLE users_tmp;

总结

以上是各种执行 PGSQL 批量更新的方案,个人的推荐度是 插入更新 > 子表 > 实体表 > 临时表。

插入更新比较推荐的理由是这种方案 SQL 写起来结构比较清晰

最不推荐的是临时表放哪,因为此种方案如果频繁执行,会导致 PG 系统表数据膨胀!

PGSQL 批量更新的更多相关文章

  1. SQL批量更新 关系表更新

    很多人在做数据的批量更新时..如果更新的内容是从其他表查出来的..很容易这么写.. UPDATE TABLE1 SET COLUMN1=(SELECT SUM(SOMETHING) FROM TABL ...

  2. SQL 将2张不相关的表拼接成2列,批量更新至另一张表

    update SO_Master set LotteryNo=t2.LotteryNo,UpdateTime=GETDATE() --select sm.LotteryNo,sm.SysNo,t2.L ...

  3. [PDO绑定参数]使用PHP的PDO扩展进行批量更新操作

    最近有一个批量更新数据库表中某几个字段的需求,在做这个需求的时候,使用了PDO做参数绑定,其中遇到了一个坑. 方案选择 笔者已知的做批量更新有以下几种方案: 1.逐条更新 这种是最简单的方案,但无疑也 ...

  4. Ado.net[登录,增删改查,Get传值,全选,不选,批量删除,批量更新]

    [虽然说,开发的时候,我们可以使用各种框架,ado.net作为底层的东西,作为一个合格的程序员,在出问题的时候我们还是要知道如何调试] 一.增删改查 cmd.ExecuteReader();执行查询, ...

  5. MongoDB学习笔记~大叔分享批量添加—批量更新—批量删除

    回到目录 说它是批量操作,就是说将集合对象一次提交到服务器,并对数据进行持久化,如果您的代码是一次一次的提交,那不算是批量操作!在之前的mongodb仓储中并没有对批量更新和批量删除进行实现,而今天在 ...

  6. jdbc-批量插入、批量删除、批量更新

    一.JDBC的批量插入 JDBC批量插入主要用于数据导入和日志记录因为日志一般都是先写在文件下的等.    我用Mysql5.1.5的JDBC driver 分别对三种比较常用的方法做了测试   方法 ...

  7. MYSQL 处理批量更新数据的一些经验。

    首先,我们需要了解下MYSQL CASE EXPRESSION 语法. 手册传送门:http://dev.mysql.com/doc/refman/5.7/en/control-flow-functi ...

  8. mybatis执行批量更新update

    Mybatis的批量插入这里有http://ljhzzyx.blog.163.com/blog/static/38380312201353536375/.目前想批量更新,如果update的值是相同的话 ...

  9. postgres 批量更新内容

    在程序中遇到这样的需求, 数据库表格式如下 需要把批量更新status, 如name = fox 时, status = 1, name = boa 时,status = 2 .... 类似的 pos ...

  10. [转]MySQL批量更新死锁案例分析

    文章出处:http://blog.csdn.net/aesop_wubo/article/details/8286215 问题描述 在做项目的过程中,由于写SQL太过随意,一不小心就抛了一个死锁异常, ...

随机推荐

  1. Beautiful code and beautiful life

    You may ask me why do i strive constantly, what i am striving for? Yep, the same question haunts me ...

  2. GIM发布新版本了 (附rust CLI制作brew bottle流程)

    GIM 发布新版本了!现在1.3.0版本可用了 https://github.com/davelet/git-intelligence-message/releases/tag/v1.3.0 .可以通 ...

  3. PHP MD5强碰撞

    MD5强碰撞 搬得这个师傅的 https://www.cnblogs.com/kuaile1314/p/11968108.html 可以看到,使用了三个等号,这个时候PHP会先检查两边的变量类型,如果 ...

  4. odoo16里面修改tree视图样式

    一.在static文件夹下新建一个css文件夹并将*.css文件写入 /*该文件用来定义视图中的一些格式,需要用到的地方直接在xml文件中进行引用*/ /*语法说明*/ /* table th:nth ...

  5. Linux日志 查找关键字及其前后的信息

      文章<五分钟扫盲:25个工作中常用的Linux命令>介绍了常用的Linux命令,属于理论知识,这里知行合一,介绍如何从Linux日志中通过关键字过滤出我们需要的信息.   这里以查看名 ...

  6. Qt 的一个大坑:visual studio中setStyleSheet不支持jpg

    在代码中设置QWidget的背景图,一般会使用setStyleSeeht函数去设置样式表: border-image:("c:x.png"); 这里有个大坑:不支持jpg图片!

  7. python播放mp3最佳方法

    使用playsound库 1 from playsound import playsound 2 3 playsound('xx.mp3') 音质很好,就是只能播放mp3

  8. 在java中动态执行js代码

    说明 在jdk11就标注了要取消NashornScriptEngineFactory类,在jdk17正式移除,所以在17上得加入pom依赖 <dependency> <groupId ...

  9. Windows下使用syscall.SIGUSR1报错:SIGUSR1 not declared by package syscall

    windows打开hyperledger/fabric项目时,\fabric\integration\e2e\e2e_signal_test.go中的syscall.SIGUSR1会报错. 这是因为 ...

  10. Java IO<3>处理流:缓冲流 数据流 转换流 对象流

    Java io 处理流 节点流和处理流概述 Java流可以分节点流和处理流两类. 节点流是面向各种物理节点的流,比如面向读写文件的FileInputStream和FileOutputStream:面向 ...