Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >如何在PostgreSQL中更新大表

如何在PostgreSQL中更新大表

作者头像
蒋老湿
修改于 2019-12-09 06:46:45
修改于 2019-12-09 06:46:45
4.9K0
举报
文章被收录于专栏:技术栈技术栈

本文来源:www.codacy.com/blog/how-to…

在Postgres中更新大型表并不像看起来那样简单。如果您的表包含数亿行,您将发现很难及时进行简单的操作,例如添加列或更改列类型。

在不停机的情况下进行这类操作是一个更大的挑战。在这篇博客文章中,我将尝试概述一些策略,以在管理大型数据集的同时最大程度地减少表不可用性。

一般准则

当您更新列中的值时,Postgres将在磁盘中写入一个新行,弃用旧行,然后继续更新所有索引。此过程等同于INSERT加上每一行后再DELETE,这会占用大量资源。

除此之外,需要更新大表时还应了解的事项列表:

  • 从头开始创建新表比更新每一行要快。顺序写比稀疏更新快,并且最后不会出现死行。
  • 表约束和索引严重延迟了每次写入。如果可能,应在更新运行时删除所有索引,触发器和外键,并在最后重新创建它们。
  • 添加没有默认值的可空列是一种廉价的操作。写入列的实际数据是昂贵的部分。
  • 更新行时,不会重写存储在TOAST中的数据
  • 从Postgres 9.2开始,在某些数据类型之间进行转换不需要重写整个表。例如:从VARCHAR(32)转换为VARCHAR(64)。

考虑到这一点,让我们看一些可以用来有效更新表中大量数据行的策略:

增量更新

如果您可以使用例如顺序ID对数据进行细分,则可以批量更新行。由于您只需要保持较短时间的锁定,因此可以最大化表的可用性。如果添加新列,则可以将其临时设置为可为空,然后开始逐渐用新值填充它。

这种方法的主要问题是性能,这是一个非常缓慢的过程,因为就地更新成本很高。在迁移期间,它可能还需要更复杂的应用程序逻辑。

创建一个新表

更新大表的最快方法是创建一个新表。

如果可以安全地删除现有表,并且有足够的磁盘空间,则执行更新的最简单方法是将数据插入到新表中,然后对其进行重命名。以下是此操作的基本执行脚本:

代码语言:txt
AI代码解释
复制
create table user_info_copy (LIKE user_info INCLUDING INDEXES INCLUDING COMMENTS);

INSERT INTO user_info_copy
SELECT user_no, idcard_no, real_name, bankcard_no, bind_mobile
     , false, bind_status, user_identity, create_time, creator
     , edit_time, editor, is_del, VERSION, customer_id
     , id_card_type, source_id, platform_no, one_passport_no, bank_code
FROM user_info;

drop TABLE user_info;

alter table user_info_copy rename to user_info;

重新创建现有表

如果由于不想重新创建视图或由于其他限制而不能删除原始表,则可以使用临时表保存新值,截断旧表并在那里重写数据。当您有未决的写请求时,此方法也有一些优点,如我们将在下一部分中看到的。

如果您的表可以容纳在内存中,则应在此事务期间增加temp_buffers属性。使用RAM代替磁盘来存储临时表将明显提高性能:

SET temp_buffers = 3000MB; ----相应地更改此值

代码语言:txt
AI代码解释
复制
# 创建临时表
CREATE TABLE temp_user_info(  
   user_no BIGINT,  
   PRIMARY KEY( user_no )  
);
# 如果需要提速可以从表中删除索引
# 复制数据到临时表中
insert into temp_user_info select user_no from user_info;

# 改变表结构,比如需要添加新列
TRUNCATE user_no;
# 执行插入列字段语句
# 再把数据反写到user_info表

处理并发写入

即使进行了上述优化,重新创建表仍然是缓慢的操作。如果您正在实时数据库中运行查询,则可能需要处理并发写入请求。

最简单的方法是在事务期间在表上强制使用SHARE LOCK, 语句如下

代码语言:txt
AI代码解释
复制
LOCK TABLE user_info IN SHARE MODE;

如果花费太长时间,所有写请求将一直等到锁释放或超时为止。如果未删除原始表,则一旦事务结束,将执行未超时的请求。请注意,即使使用相同的名称创建新表,请求仍将失败,因为它们使用表OID

根据写请求的性质,您还可以创建自定义规则来存储对表所做的更改。例如,您可以设置一个规则,以在开始数据迁移之前记录已删除的行:

代码语言:txt
AI代码解释
复制
CREATE RULE deleted_rule AS ON DELETE
TO tbl
DO INSERT INTO tbl_deletes VALUES
(
  OLD.id
);

迁移结束时,您只需从tbl_deletes中读取ID,然后在新表上将其删除。可以使用类似的方法来处理其他类型的请求。

结论

一旦达到一定大小,曾经瞬时的操作可能需要几个小时来准备和执行。个人实验结论:

  • 用存储过程批量更新 560w , 1455秒结束
  • 用复制表改名方法操作 560w数据, 120秒左右就结束了;
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019年10月31日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
聊聊PostgreSQL表膨胀
PostgreSQL Basic PG中的MVCC(多版本并发)设计目的是读不阻塞写。PG中的所有的insert和update操作都是创建新的一行数据;update和delete都不是立即删除旧版本无用的数据。tuple是否可见是由snapshot决定。 PG中追踪每个表的Block可见性是通过表的vm文件。Table或者Index的可用空间管理是通过表或者索引的fsm文件管理,它是一个2级的binary tree,最底层存储了每个page可用空间,最上层聚合最低层的信息。 PG目前支持多种
用户4700054
2023/02/26
1.8K0
聊聊PostgreSQL表膨胀
数据湖(十五):Spark与Iceberg整合写操作
"insert into"是向Iceberg表中插入数据,有两种语法形式:"INSERT INTO tbl VALUES (1,"zs",18),(2,"ls",19)"、"INSERT INTO tbl SELECT ...",以上两种方式比较简单,这里不再详细记录。
Lansonli
2022/07/10
1.8K0
数据湖(十五):Spark与Iceberg整合写操作
PostgreSQL技术大讲堂 - 第32讲:数据库参数调整
PostgreSQL从小白到专家,是从入门逐渐能力提升的一个系列教程,内容包括对PG基础的认知、包括安装使用、包括角色权限、包括维护管理、、等内容,希望对热爱PG、学习PG的同学们有帮助,欢迎持续关注CUUG PG技术大讲堂。
用户5892232
2023/11/03
4120
PostgreSQL技术大讲堂 - 第32讲:数据库参数调整
Postgresql存储结构
如果阅读过手册一定听过postgresql cluster的概念,第一次听到这个概念可能都会有一些困惑。cluster在安装数据库时,由initdb工具生成,initdb后产生的pgdata文件夹可以理解为cluster的物理存储结构。数据库启动、停止时pg_ctl -D参数指定的文件夹即cluster文件夹,所以一个PG Server可以运行在一个PG Cluster上。
mingjie
2022/05/12
1.2K0
Postgresql存储结构
POSTGRESQL 创建一个表到底有什么说的? 可说的挺多的
创建一张表,到底有什么说的, 下面是POSTGRESQL 创建数据表的官方文档的内容截图. 那我们就往下看,到底我们可以说点什么
AustinDatabases
2021/07/15
7750
POSTGRESQL 创建一个表到底有什么说的?  可说的挺多的
Postgresql中的MVCC与并发
ACID中的C即一致性在PG内部使用MVCC机制来保证。MVCC多版本并发控制为数据加上时间戳,读写需要额外的根据自身时间戳与数据时间戳对比,按照既定的规则可以知道这条数据对当前的SQL是否可见。MVCC避免了传统的锁方法,将锁竞争最小化来获得更高的性能。
mingjie
2022/05/12
3.9K0
Postgresql中的MVCC与并发
PostgreSQL逻辑复制之pglogical篇
pglogical 是 PostgreSQL 的拓展模块, 为 PostgreSQL 数据库提供了逻辑流复制发布和订阅的功能。 pglogical 重用了 BDR 项目中的一部分相关技术。pglogical 是一个完全作为PostgreSQL 扩展实现的逻辑复制系统。完全集成,它不需要触发器或外部程序。这种物理复制的替代方法是使用发布/订阅模型复制数据以进行选择性复制的一种高效方法。支持 PG10、9.6、9.5、9.4 ,提供比 Slony、Bucardo 或 Londiste 更快的复制速度,以及跨版本升级。 我们使用的下列术语来描述节点和数据流之间的关系,重用了一些早期的 Slony 技术中的术语:
星哥玩云
2022/08/18
2.2K0
PostgreSQL表膨胀终结者
PostgreSQL数据库表在删除数据后磁盘空间未释放,该怎么办? 主流的压缩表工具有哪些?该如何选择?
俊才
2021/04/22
1.4K0
PostgreSQL表膨胀终结者
盘点开发中那些常用的MySQL优化
(1)对于MyISAM存储引擎的表,可以使用:DISABLE KEYS 和 ENABLE KEYS 用来打开或者关闭 MyISAM 表非唯一索引的更新。
全栈程序员站长
2022/07/12
5140
盘点开发中那些常用的MySQL优化
MySql数据库Update批量更新与批量更新多条记录的不同值实现方法
这里注意 ‘other_values' 是一个逗号(,)分隔的字符串,如:1,2,3
Lansonli
2021/10/09
21.8K0
Postgresql垃圾回收原理分析
间隔删除数据,使用ctid(页面号,lp号)作为条件,发现数据并没有真正的从页面中删除
mingjie
2022/05/12
8480
Postgresql垃圾回收原理分析
Ubuntu PostgreSQL安装和配置
config /etc/postgresql/9.5/main data /var/lib/postgresql/9.5/main locale en_US.UTF-8 socket /var/run/postgresql port 5432
qubianzhong
2019/07/01
1.8K0
Ubuntu PostgreSQL安装和配置
PostgreSQL列存增加更新和删除功能
Hydra是企业级数据仓库的开源替代品。速度快且功能丰富,开发人员可以更快的构建更好的分析。支持列存PG的更新和删除是#1客户功能请求,现在GA了。之前博文“如何为分析构建最快的PG数据库”中,回顾了Hydra团队如何将列存、向量化和查询并行化添加到PG中,以及使用ClickBench的基准测试结果。目前对WHERE进行了向量化。但未用SIMD,声称很快会提供。平均下来,查询性能比基本PG提高了23倍!这也太夸张了吧,可以弄下来测试下,文末有源码地址。
yzsDBA
2023/05/25
1.2K0
PostgreSQL列存增加更新和删除功能
PG 13新特性汇总
PostgreSQL 10 版本开始支持逻辑复制,在12版本之前逻辑复制仅支持普通表,不支持分区表,如果需要对分区表进行逻辑复制,需单独对所有分区进行逻辑复制。
AiDBA宝典
2023/08/09
1.3K0
PG 13新特性汇总
MySQL 数据库 增删查改、克隆、外键 等操作
char 最多支持 255 个字符,char 如果存入数据的实际长度比指定长度要小,会补空格至指定长度;如果存入的数据的实际长度大于指定长度,低版本的 Mysql 会被截取前 255个 字符,高版本会报错。
全栈程序员站长
2022/09/01
5.9K0
MySQL 数据库 增删查改、克隆、外键 等操作
MYSQL库,表,记录的基本操作
  mysql – 用户权限相关数据   test – 用于用户测试数据   information_schema – MySQL本身架构相关数据
全栈程序员站长
2022/07/21
1.7K0
MYSQL库,表,记录的基本操作
PostgreSQL新手入门
自从MySQL被Oracle收购以后,PostgreSQL逐渐成为开源关系型数据库的首选。 本文介绍PostgreSQL的安装和基本用法,供初次使用者上手。以下内容基于Debian操作系统,其他操作系
ruanyf
2018/04/13
1.3K0
PostgreSQL新手入门
Python SQLite 基本操作和经验技巧(一)
在一个 C/C++ 程序中(或者脚本语言使用 Tcl/Ruby/Perl/Python 等) 你可以在一个特殊的名叫 SQLITE_MASTER 上执行一个SELECT查询以获得所有 表的索引。每一个 SQLite 数据库都有一个叫 SQLITE_MASTER 的表, 它定义数据库的模式。 SQLITE_MASTER 表看起来如下:
cutercorley
2020/07/23
5.3K0
进阶数据库系列(十):PostgreSQL 视图与触发器
视图(View)本质上是一个存储在数据库中的查询语句。视图本身不包含数据,也被称为虚拟表。 我们在创建视图时给它指定了一个名称,然后可以像表一样对其进行查询。
民工哥
2023/08/22
1.3K0
进阶数据库系列(十):PostgreSQL 视图与触发器
流数据湖平台Apache Paimon(二)集成 Flink 引擎
Paimon目前支持Flink 1.17, 1.16, 1.15 和 1.14。本课程使用Flink 1.17.0。
Maynor
2023/07/31
3K0
流数据湖平台Apache Paimon(二)集成 Flink 引擎
相关推荐
聊聊PostgreSQL表膨胀
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档