PostgreSQL MVCC的弊端优化方案

我们之前的博客文章“我们最讨厌的 PostgreSQL 部分”讨论了大家最喜欢的 DBMS 多版本并发控制 (MVCC) 实现所带来的问题。其中包括版本复制、表膨胀、索引维护和真空管理。本文将探讨针对每个问题优化 PostgreSQL 的方法。

尽管 PostgreSQL 的 MVCC 实现是 Oracle 和 MySQL 等其他广泛使用的数据库中最差的,但它仍然是我们最喜欢的 DBMS,而且我们仍然喜欢它!通过分享我们的见解,我们希望帮助用户释放这个强大的数据库系统的全部潜力。好消息是 OtterTune 会自动为您解决许多此类问题(但不是全部!)。

问题#1:版本复制

当查询修改元组时,无论更新其一列还是所有列,PostgreSQL 都会通过复制其所有列来创建新版本。这种复制可能会导致大量数据重复并增加存储需求,特别是对于具有许多列和较大行大小的表。

优化:不幸的是,如果不对 PostgreSQL 的内部结构进行重大重写(这会造成破坏),就没有解决此问题的解决方法。这不像在情景喜剧中替换了一个没有人注意到的角色。正如我们在上一篇文章中提到的,EnterpriseDB 在 2013 年通过 zheap 项目开始了这条道路,但该项目的最后一次更新是在 2021 年。其他人已经对 PostgreSQL 代码进行了硬分叉,以取代其 MVCC 实现。著名的例子包括 OrioleDB 和 YugabyteDB。但对这些系统的更改永远不会合并回主 PostgreSQL 代码库。所以我们暂时只能使用 PostgreSQL 的append-only MVCC。

Problem #2: Table Bloat 问题#2:表膨胀

PostgreSQL 将过期版本(死元组)和活动元组存储在同一页面上。尽管 PostgreSQL 的 autovacuum 工作程序最终会删除这些死元组,但写入繁重的工作负载可能会导致它们累积的速度快于真空处理的速度。此外,自动清理仅删除死元组以供重用(例如,存储新版本),并且不会回收未使用的存储空间。在查询执行期间,PostgreSQL 将死元组加载到内存中(因为 DBMS 将它们与活元组混合在页面上),从而增加磁盘 IO 并损害性能,因为 DBMS 检索无用的数据。如果您正在运行 Amazon 的 PostgreSQL Aurora,这将增加 DBMS 的 IOPS,并导致您给 Jeff Bezos(amazon的老板) 更多的钱!

优化:我们建议监控 PostgreSQL 的表膨胀,然后定期回收未使用的空间。 内置pgstattuple模块可以准确计算数据库中的可用空间,但它需要全表扫描,这对于生产环境中的大表来说不实用。

$ psql -c "CREATE EXTENSION pgstattuple" -d $DB_NAME
$ psql -c "SELECT * FROM pgstattuple('$TABLE_NAME')" -d $DB_NAME

或者,可以使用一次性查询或脚本来估计表的未使用空间;它们比 pgstattuple 更快、更轻量,因为它们提供了表膨胀的粗略估计。如果未使用的空间量很大,则 pg_repack 扩展会从臃肿的表和索引中删除并回收页面。它在线工作,不需要在处理过程中对表进行独占锁定(与 VACUUM FULL 不同)。

以下命令将把 pg_repack 扩展安装到自我管理的 DBMS 中(请参阅 Amazon 的 PostgreSQL RDS 说明),然后压缩单个表。

$ psql -c "CREATE EXTENSION pg_repack" -d $DB_NAME
$ pg_repack -d $DB_NAME --table $TABLE_NAME

为了最大限度地减少对数据库性能的潜在影响,OtterTune 建议我们的客户在流量较低的非高峰时段启动此过程。

问题#3:二级索引维护

当应用程序对表执行 UPDATE 查询时,PostgreSQL 还必须更新该表的所有索引以将条目添加到新版本。这些索引更新增加了 DBMS 的内存压力和磁盘 I/O,特别是对于具有大量索引的表(一位 OtterTune 客户在单个表上有 90 个索引!)。随着表中索引数量的增加,更新元组时产生的开销也会增加。 PostgreSQL 避免更新仅堆元组 (HOT) 更新的索引,其中 DBMS 将新版本存储在与先前版本相同的页面上。但正如我们在上一篇文章中提到的,OtterTune 客户的 PostgreSQL 数据库仅对 46% 的更新操作使用 HOT 优化。

优化:减少 PostgreSQL 索引写入放大的明显解决方法是减少每个表的索引数量。但这说起来容易做起来难。我们建议从表中重复和未使用的索引开始。人们可以通过检查数据库的模式来识别重复索引,以查看两个索引是否以相同的顺序引用相同的列并使用相同的数据结构(例如,B+树与哈希表)。对于未使用的索引,PostgreSQL 维护索引级指标(例如,pg_stat_all_indexes.idx_scan),用于跟踪在索引上启动的索引扫描的数量。如果索引的该值为零,则所有应用程序的查询都不会使用该索引。确保忽略未使用的主键或唯一索引,因为 DBMS 使用它们对表强制执行完整性约束。

下面的屏幕截图显示了 OtterTune 的类似检查,用于自动查找不必要的索引。

OtterTune’s Unused and Duplicate index dashboard.
OtterTune 的未使用和重复索引仪表板。

一旦确定要删除的索引,下一步就是删除它们。但是,如果您的应用程序使用对象关系映射 (ORM) 框架来管理其数据库架构,那么您不希望手动删除索引,因为 ORM 可能会在将来的架构迁移期间重新创建索引。在这种情况下,有必要更新应用程序代码中的架构。如果应用程序未使用 ORM,则可以使用 DROP INDEX 命令。

问题#4:真空管理

PostgreSQL 的性能在很大程度上取决于其 autovacuum 清理过时数据和修剪 MVCC 方案中版本链的有效性。然而,由于其复杂性,配置自动清理以正确运行并及时删除这些数据具有挑战性。默认的全局自动清理设置不适合大型表(数百万到数十亿的元组),因为触发清理可能需要很长时间。此外,如果每个 autovacuum 调用需要很长时间才能完成或被长时间运行的事务阻塞,DBMS 将积累死元组并遭受陈旧统计数据的影响。将自动清理延迟太久会导致查询随着时间的推移逐渐变慢,需要手动干预来解决该问题。

优化:虽然在 PostgreSQL 中清理表很痛苦,但好消息是它是可以管理的。但正如我们现在所讨论的,这有很多步骤,并且需要跟踪很多信息。

控制 autovacuum 的第一步是监视每个表的死元组数量。 PostgreSQL 的  pg_stat_all_tables视图提供了监控表的基本指标,包括死元组 ( n_dead_tup ) 和活动元组 ( n_live_tup ) 数量的估计。通过此类表级指标,您可以确定每个表过期元组的百分比,并确定哪些表需要额外的清理工作。

对于具有大量死元组的表,您可以调整其设置以使 PostgreSQL 更频繁地触发 autovacuum。 PostgreSQL 允许您在表级别微调 autovacuum 参数,不同的表可能需要不同的最佳设置。最重要的旋钮是 autovacuum_vacuum_scale_factor:它指定在 PostgreSQL 调用 autovacuum 之前表中必须存在的死元组的最小百分比。该旋钮的默认值为 20%。如果应用程序的一个表有 10 亿个元组,PostgreSQL 不会在该表上运行清理,直到至少有 2 亿个死元组。如果该表中的平均元组大小为 1KB,则 2 亿个死元组将消耗 200GB 的磁盘存储空间。这甚至不包括指向这些表的索引指针的额外存储开销!为了避免此问题,您应该使用 ALTER TABLE SQL 命令将大型表的比例因子旋钮设置为小于 20%:

 ALTER TABLE table_name SET (autovacuum_ vacuum_scale_factor = 0.05);

接下来,您应该检查 autovacuum 是否被长时间运行的事务阻塞。再次,我们可以依靠 PostgreSQL 的内部遥测来获取这些信息。 pg_stat_activity 视图提供每个 PostgreSQL 工作线程(即进程)当前执行状态的实时数据。它显示每个活动事务已运行多长时间。如果事务已经运行了几个小时,您应该考虑将其终止,以便 autovacuum 可以完成其操作。下面的示例查询查找所有运行时间超过五分钟的事务:

SELECT pid, NOW() - xact_start AS duration, query, state
  FROM pg_stat_activity
 WHERE (NOW() - xact_start) > INTERVAL '5 minutes';

然后,您可以使用 pg_cancel_backend 管理函数终止查询:

SELECT pg_cancel_backend($PID_TO_KILL);

当然,在街上删除查询可能会产生意想不到的后果,因此您必须确保杀死它们不会在您的应用程序中造成问题。为了避免将来出现同样的问题,请确保事务的查询不必要地运行更长的时间,因为它们使用的是低效的查询计划。请参阅我们之前关于优化查询性能的文章,例如欺骗 ORDER BY...LIMIT 和运行 ANALYZE ,了解如何使用 OtterTune 改善慢速查询。如果您不需要它们是原子的,您还可以重构您的应用程序,将大型事务分解为较小的工作单元(但不可否认,这并不总是容易做到)。

最后,您需要查看是否存在长时间运行的真空过程,然后调整其他旋钮。与 pg_stat_activity 显示 PostgreSQL 工作线程的状态类似,pg_stat_progress_vacuum 视图显示活动 autovacuum 操作的状态。通过此视图,您可以确定真空是否需要几个小时甚至几天才能完成。如果您的 PostgreSQL DBMS 确实有长时间运行的 Vacuum,那么 OtterTune 建议调整三个旋钮:

  1. autovacuum_work_mem 参数指定 DBMS 在每次 autovacuum 调用中可以使用的最大内存量。增加此参数可以加快清理速度,因为它可以在每次调用时修剪更多的死元组。
  2. autovacuum_vacuum_cost_limit 参数控制在 PostgreSQL 强制自动清理工作者暂时退出之前可以产生多少 I/O 活动自动清理工作者。该旋钮的值越高意味着自动清理将更加积极。
  3. 与这种基于成本的控制机制相关,autovacuum_vacuum_cost_delay  参数确定 autovacuum 工作线程在 DBMS 强制其退出后必须等待多长时间。较短的延迟意味着自动清理每次都会更快地恢复操作。

原文地址

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/39801.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在Appium中使用AI定位

当我们在写自动化测试脚本的时候,传统情况下一定要知道元素的属性,如id、name、class等。那么通过AI的方式定位元素可能就不需要知道元素的属性,评价人对元素的判断来定位,比如,看到一个搜索框,直接使用ai:…

【无标题】使用html2canvas和jspdf生成的pdf在不同大小的屏幕下文字大小不一样

问题:使用html2canvas和jspdf生成的pdf在不同大小的屏幕下文字大小不一样,在mac下,一切正常,看起来很舒服,但是当我把页面放在扩展屏幕下(27寸),再生成一个pdf,虽然排版一…

【算法基础:数据结构】2.3 并查集

文章目录 并查集算法原理(重要!⭐) 经典例题836. 合并集合(重要!模板!⭐)837. 连通块中点的数量(维护连通块大小的并查集)240. 食物链(维护额外信息的并查集&…

【AI绘画】AI绘画乐趣:稳定增强扩散技术展现

目录 前言一、Stable Diffusion是什么?二、安装stable-diffusion-webui1. python安装2. 下载模型3. 开始安装:4. 汉化:5. 模型使用:6. 下载新模型:7. 基础玩法 三、总结 前言 本文将借助stable-diffusion-webui项目来…

【数据结构与算法】哈夫曼编码(最优二叉树)实现

哈夫曼编码 等长编码:占的位置一样 变长编码(不等长编码):经常使用的编码比较短,不常用的比较短 最优:总长度最短 最优的要求:占用空间尽可能短,不占用多余空间,且不…

网络版计算器

本次我们实现一个服务器版本的简单的计算器,通过自己在应用层定制协议来将数据传输出去。 协议代码 此处我们为了解耦,采用了两个类,分别表示客户端的请求和服务端的响应。 Request class Request { public:Request(){}Request(int x, int…

Unity 任意数据在Scene窗口Debug

任意数据在Scene窗口Debug 🍔效果🥪食用方法 🍔效果 如下所示可以很方便的把需要Debug的数据绘制到Scene中(普通的Editor脚本只能够对MonoBehaviour进行Debug) 🥪食用方法 💡. 新建脚本继承Z…

实例018 类似windows xp的程序界面

实例说明 在Windows XP环境下打开控制面板,会发现左侧的导航界面很实用。双击展开按钮,导航栏功能显示出来,双击收缩按钮,导航按钮收缩。下面通过实例介绍此种主窗体的设计方法。运行本例,效果如图1.18所示。 ​编辑…

如何顺势而为,让ChatGPT为教育所用?

恐惧和回避无法阻挡科技的浪潮,教育与AI的深度融合时代已经到来,如何把AI当做工具,把其成为教育的机会而非威胁,是教育体系未来不得不得面对的新变化。 接受ChatGPT作为一种教学辅助工具,成为教师的朋友或者帮手&…

Leetcode每日一题:979. 在二叉树中分配硬币(2023.7.14 C++)

目录 979. 在二叉树中分配硬币 题目描述: 实现代码与解析: dfs(后序遍历) 原理思路: 979. 在二叉树中分配硬币 题目描述: 给定一个有 N 个结点的二叉树的根结点 root,树中的每个结点上都对…

5.postgresql--COALESCE

在 PostgreSQL 中, COALESCE函数返回第一个非空参数。它通常与 SELECT 语句一起使用以有效处理空值。 COALESCE函数接受无限数量的参数。它返回第一个不为空的参数。如果所有参数都为 null,则 COALESCE函数将返回 null。 COALESCE函数从左到右计算参数&a…

doris恢复库恢复表

今天眼疾手快 不小心删了公司生产环境的表 而且碰巧这个数据没有备份的 当时哥们就呆住 还好doris升级过1.2 刚推出了恢复数据的功能~~~~~这里给老天爷磕一个了~~~~~~ 数据删除恢复 Doris为了避免误操作造成的灾难,支持对误删除的数据库/表/分区进行数据恢复&…

MongoDB初体验-安装使用教程2023.7

前言:博主第一次接触MongoDB,看了一圈网上现有的教程,不是缺少细节就是有问题没交代清楚,特整理了一下自己安装运行的过程,从下载安装到开机自启,全程细节齐全、图文并茂、简单易懂。 目录 1. 从官网下载2…

JavaWeb课程设计项目实战(03)——开发准备工作

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl 在正式进入项目开发之前请先完成以下准备工作。 数据库语句 请创建数据库和表并完成数据初始化工作。 初始化数据库 请在MySQL数据库中创建名为studentinformationmanag…

Nacos服务注册和配置中心(Config,Eureka,Bus)1

SCA(Spring Cloud Alibaba)核心组件 Spring Cloud是若干个框架的集合,包括spring-cloud-config、spring-cloud-bus等近20个子项目,提供了服务治理、服务网关、智能路由、负载均衡、断路器、监控跟踪、分布式消息队列、配置管理等领域的解决方案,Spring C…

ADB 命令结合 monkey 的简单使用,超详细

一:ADB简介 1,什么是adb: ADB 全称为 Android Debug Bridge,起到调试桥的作用,是一个客户端-服务器端程序。其中客户端是用来操作的电脑,服务端是 Android 设备。ADB 也是 Android SDK 中的一个工具&…

unity背景缓动动效

这算是一个很常见的小功能,比如我们在玩横版游戏的时候,背景动画会以一定的频率运动,其实现方式也有很多种。 比如,使用UGUI的imageanimtion动画的方式,自己k桢实现。 还可以使用材质球本身的功能来实现,关…

【MySQL】查询进阶

查询进阶 数据库约束约束类型NULL , DEFAULT , UNIQUE 约束主键约束外键约束 聚合查询聚合函数group by子句HAVING 联合查询内连接外连接自连接子查询单行子查询多行子查询 数据库约束 约束类型 NOT NULL #表示某行不能储存空值 UNIQUE #保证每一行必须有唯一的值 DEFAULT #规…

UnxUtils工具包,Windows下使用Linux命令

1. 前言 最近写批处理多了,发现Windows下的bat批处理命令,相比Linux的命令,无论是功能还是多样性,真的差太多了。但有时候又不得不使用bat批处理,好在今天发现了一个不错的工具包:UnxUtils,这个…

【Java/大数据】Kafka简介

Kafka简介 Kafka概念关键功能应用场景 Kafka的原理Kafka 的消息模型早期的队列模型发布-订阅模型Producer、Consumer、Broker、Topic、PartitionPartitionoffsetISR Consumer Groupleader选举Controller leaderPartition leader producer 的写入流程 多副本机制replicas的同步时…