概述

在我们的平常业务中,经常需要批量更新数据,例如:现阶段需要更新 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. K8S+nginx+MYSQL+TOMCAT高可用架构企业自建网站

    以下是基于 多Master高可用Kubernetes集群 的企业级部署详细步骤,涵盖 Nginx Ingress + MySQL高可用集群 + Tomcat负载均衡 的完整流程: 一.前置条件准备 1 ...

  2. JuiceFS v1.3-Beta1:一亿文件备份分钟级完成,性能优化全解析

    在最新发布的 JuiceFS v1.3 Beta1 版本中,我们引入了一种全新的二进制备份机制,旨在更高效地应对亿级文件规模下的备份与迁移场景.相比现有的 JSON 备份方式,该机制在导入导出元数据时 ...

  3. AWK用法全解

    一.awk介绍 awk是Linux自带的一个逐行扫描的文本处理工具,支持正则表达式.循环控制.条件判断.格式化输出.AWK自身带有一些变量,可以在书写脚本时调用. 二.基本语法格式 2.1.在shel ...

  4. ubuntu下多开terminator的快捷指令

    sudo apt-get install terminator Ctrl+Shift+E 垂直分割窗口 Ctrl+Shift+O 水平分割窗口 F11 全屏 Ctrl+Shift+C 复制 Ctrl+ ...

  5. C++协程:异步编程的轻量级解决方案

    1. ​协程的本质与特性​ C++20引入的协程(Coroutines)是一种可暂停和恢复的函数,通过co_await.co_yield.co_return三个关键字实现非抢占式任务调度. 与传统线程 ...

  6. windows通过批处理让电脑每天自动设置bing桌面背景

    概要 bing搜索的背景图片每天都会进行自动更新,而且质量都非常的不错,而获取图片的api也是可以在网上找到的. { "images": [ { "startdate&q ...

  7. 使用RandomAccessFile监听日志文件,并实时一行行读取出来

    public static void main(String[] args) { String filePath = "E:\\codes\\work\\product-parent\\lo ...

  8. LogStash介绍及二进制安装

    概述 官方文档:https://www.elastic.co/guide/en/logstash/7.17/introduction.html Logstash 是一款开源数据收集引擎,具备实时流水线 ...

  9. Element-Plus官网Header类像素效果的实现

      Element-Plus官网Header类像素效果 一.前言 在使用Element-Plus时,发现有两个很有趣的效果,一个是header的背景模糊效果,另一个是黑夜模式切换动画,在此我们先来研究 ...

  10. WPF 不能识别的图标代码

    https://blog.csdn.net/YouyoMei/article/details/86702178?utm_medium=distribute.pc_relevant.none-task- ...