Greenplum的并发控制概述

2023-09-13 10:49:25

注:本文翻译自https://docs.vmware.com/en/VMware-Greenplum/7/greenplum-database/admin_guide-intro-about_mvcc.html

Greenplum数据库使用PostgreSQL多版本并发控制(MVCC)模型来管理堆表的并发事务。

数据库管理系统中的并发控制允许并发查询以正确的结果完成,同时确保数据库的完整性。传统数据库使用两阶段锁定协议,防止事务修改已被另一个并发事务读取的数据,并防止任何并发事务读取或写入另一个事务已更新的数据。协调事务所需的锁会给数据库增加争用,从而降低整体事务吞吐量。

Greenplum数据库使用PostgreSQL多版本并发控制(MVCC)模型来管理堆表的并发性。使用MVCC,每个查询在查询开始时都对数据库的快照进行操作。查询运行时,无法看到其他并发事务所做的更改。这可确保查询看到数据库的一致视图。读取行的查询永远不会阻塞等待写行的事务。相反,写行的查询不会被读行的事务阻塞。与使用锁来协调读写数据的事务之间的访问的传统数据库系统相比,这允许更高的并发性。

注:使用不同的并发控制模型管理追加优化的表。它们适用于从不或很少执行行级更新的“一次写,多次读”应用程序。

快照

MVCC模型依赖于系统管理多个版本数据行的能力。查询在查询开始时对数据库的快照进行操作。快照是在语句或事务开头可见的一组行。快照确保查询在执行期间具有一致且有效的数据库视图。

每个事务被分配一个唯一的事务ID (XID),一个递增的32位值。当一个新事务启动时,它被分配下一个XID。未包含在事务中的SQL语句被视为单语句事务—隐式地添加BEGIN和COMMIT。这类似于某些数据库系统中的自动提交。

注:Greenplum Database仅将XID值分配给涉及DDL或DML操作的事务,这些事务通常是唯一需要XID的事务。

当事务插入一行时,XID与该行一起保存在xmin系统列中。当事务删除一行时,XID保存在xmax系统列中。更新一行被视为删除和插入,因此XID被保存为当前行的xmax和新插入行的xmin。xmin和xmax列以及事务完成状态指定了一个事务范围,其中行版本是可见的。一个事务可以看到所有小于xmin的事务的效果,这些事务保证被提交,但是它不能看到大于或等于xmax的任何事务的效果。

多语句事务还必须记录事务中的哪个命令插入了一行(cmin)或删除了一行(cmax),以便事务可以看到事务中先前命令所做的更改。命令序列仅在事务期间相关,因此在事务开始时将该序列重置为0。

XID是数据库的一个属性。每个段数据库都有自己的XID序列,不能与其他段数据库的XID进行比较。协调器使用一个称为gp_session_id的集群范围的会话ID号来协调分布式事务。段维护分布式事务id与其本地xid的映射。协调器使用两阶段提交协议协调所有段中的分布式事务。如果事务在任何一个段上失败,它将在所有段上回滚。

使用SELECT语句可以看到任意一行的xmin, xmax, cmin和cmax列:

SELECT xmin, xmax, cmin, cmax, * FROM <tablename>;

因为您在协调器上运行SELECT命令,所以xid是分布式事务id。如果可以在单个段数据库中运行该命令,则xmin和xmax值将是该段的本地xid。

注:Greenplum Database将复制表的所有行分发到每个段,因此每个段上的每一行都是重复的。每个段实例为系统列xmin、xmax、cmin和cmax以及gp_segment_id和ctid维护自己的值。Greenplum数据库不允许用户查询访问复制表的这些系统列,因为它们没有一个明确的值可供查询。

事务ID回卷

MVCC模型使用事务id (xid)来确定哪些行在查询或事务的开头是可见的。XID是一个32位值,因此在该值溢出并归零之前,数据库理论上可以运行超过40亿个事务。然而,Greenplum数据库对xid使用模232算法,它允许事务id进行回卷装,就像时钟在12点钟回卷一样。对于任何给定的XID,可能有大约20亿个过去的XID和20亿个未来的XID。这种方法一直有效,直到一行的某个版本持续了大约20亿个事务,这时它突然出现为一个新行。为了防止这种情况,Greenplum有一个特殊的XID,称为FrozenXID,它总是被认为比与之比较的任何常规XID更老。在20亿个事务中,一行的xmin必须替换为FrozenXID,这是VACUUM命令执行的功能之一。

至少每20亿个事务清理一次数据库可以防止XID回卷。Greenplum数据库监视事务ID,并在需要VACUUM操作时发出警告。
当事务ID的很大一部分不再可用并且在事务ID环绕发生之前发出警告:

WARNING: database "<database_name>" must be vacuumed within <number_of_transactions> transactions

当发出警告时,需要进行VACUUM操作。如果没有执行VACUUM操作,Greenplum数据库将停止创建事务,以避免在事务ID环绕发生之前达到限制并发出此错误时可能出现的数据丢失:

FATAL: database is not accepting commands to avoid wraparound data loss in database "<database_name>"

当出现警告和错误时,服务器配置参数xid_warn_limit和xid_stop_limit控制。xid_warn_limit参数指定发出警告时在xid_stop_limit之前的事务id的数量。xid_stop_limit参数指定了当发出错误且无法创建新事务时,在发生环绕之前的事务id数。

事务隔离级别

SQL标准定义了事务隔离的四个级别。最严格的是Serializable,该标准将其定义为任何一组Serializable事务的并发执行都保证产生与以某种顺序一次运行一个事务相同的效果。其他三个级别是根据并发事务之间的交互产生的现象来定义的,这种交互不能在每个级别上发生。该标准指出,由于Serializable的定义,在该级别上不可能出现这些现象。

各级禁止的现象有:

  • 脏读——事务读取并发未提交事务写入的数据。
  • 不可重复读取——事务重新读取它以前读过的数据,并发现数据已被另一个事务(自初始读取以来提交的事务)修改。
  • 幻读—事务重新执行查询,返回满足搜索条件的行集,并发现满足条件的行集由于最近提交的另一个事务而发生了更改。
  • 序列化异常——成功提交一组事务的结果与每次运行这些事务的所有可能顺序不一致。

Greenplum数据库只实现两个不同的事务隔离级别,尽管您可以请求所描述的四个级别中的任何一个。Greenplum数据库READ UNCOMMITTED级别的行为类似于READ COMMITTED,而SERIALIZABLE级别则回落到REPEATABLE READ。
该表还显示了Greenplum数据库的REPEATABLE READ实现不允许幻读。这在SQL标准下是可以接受的,因为标准规定了在某些隔离级别上不能发生哪些异常;更高的保证是可以接受的。

重要:一些Greenplum数据库数据类型和函数有关于事务行为的特殊规则。特别是,对序列所做的更改(因此使用serial声明的列的计数器)对所有其他事务都是立即可见的,并且如果进行更改的事务终止,则不会回滚。

设置隔离级别

Greenplum数据库的默认事务隔离级别由default_transaction_isolation服务器配置参数指定,初始值为READ COMMITTED。
当您在会话中设置default_transaction_isolation时,您为会话中的所有事务指定默认事务隔离级别。

要设置当前事务的隔离级别,可以使用set transaction SQL命令。请确保在任何SELECT、INSERT、DELETE、UPDATE或COPY语句之前设置隔离级别:

BEGIN;
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
...
COMMIT;

也可以在BEGIN语句中指定隔离级别:

BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ;

从表中移除过期行

更新或删除一行会在表中留下该行的过期版本。当过期的行不再被任何活动事务引用时,可以删除它,并且可以重用它所占用的空间。VACUUM命令标记过期行所使用的空间以供重用。

当过期的行在表中积累时,必须扩展磁盘文件以容纳新行。由于运行查询所需的磁盘I/O增加,性能会下降。这种情况被称为膨胀,应该通过定期吸尘来处理。

VACUUM命令(不带FULL)可以与其他查询并发运行。它将过期行的先前使用的空间标记为空闲空间,并更新空闲空间映射。当Greenplum Database稍后需要为新行提供空间时,它首先查询表的空闲空间映射以查找具有可用空间的页面。如果没有找到,则将新页追加到文件中。

VACUUM(没有FULL)不会合并页或减小磁盘上表的大小。它恢复的空间只能通过空闲空间图使用。为了防止磁盘文件增长,经常运行VACUUM是很重要的。所需的VACUUM运行频率取决于表中更新和删除的频率(插入只添加新行)。频繁更新的表可能需要每天运行几次VACUUM,以确保可以通过空闲空间映射找到可用的空闲空间。在运行更新或删除大量行的事务之后运行VACUUM也很重要。

VACUUM FULL命令重写没有过期行的表,将表减小到最小大小。检查表中的每一页,并将可见行上移到尚未完全打包的页中。空页将被丢弃。表被锁定,直到VACUUM FULL完成。与常规的VACUUM命令相比,这是非常昂贵的,可以通过定期vacuum来避免或推迟。最好在维护期间运行VACUUM FULL。VACUUM FULL的另一种替代方法是使用CREATE table AS语句重新创建表,然后删除旧表。

您可以运行VACUUM VERBOSE tablename以按段获取报告,其中包含已删除的死行数、受影响的页面数以及具有可用空闲空间的页面数。

查询pg_class系统表,了解表在所有段上使用了多少页。确保首先对表进行ANALYZE以获得准确的数据。

SELECT relname, relpages, reltuples FROM pg_class WHERE relname='<tablename>';

另一个有用的工具是gp_toolkit模式中的gp_bloat_diag视图,它通过比较表使用的实际页数与预期页数来识别表中的膨胀。有关gp_bloat_diag的更多信息,请参阅Greenplum数据库参考指南中的“gp_toolkit管理模式”。

更多推荐

如何实现微服务

一、问题拆解1.1、客户端如何访问这些服务原来的Monolithic方式开发,所有的服务都是本地的,UI可以直接调用;现在按功能拆分成独立的服务,跑在独立的虚拟机上的Java进程了。客户端UI如何访问他的?后台有N个服务,前台就需要记住管理N个服务,一个服务下线/更新/升级,前台就要重新部署,这明显不符合我们拆分的理念

【LeetCode题目详解】第十章 单调栈part02 ● 503.下一个更大元素II ● 42. 接雨水 (day59补)

本文章代码以c++为例!一、力扣第503题:下一个更大元素II题目:给定一个循环数组nums(nums[nums.length-1]的下一个元素是nums[0]),返回nums中每个元素的下一个更大元素。数字x的下一个更大的元素是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的

vvic API接口接入说明:解锁新一代数据可视化的无限可能

随着大数据时代的来临,数据可视化已成为我们理解、分析和呈现复杂数据的重要手段。在这个领域中,vvic以其独特的优势,引领着数据可视化的发展潮流。其强大的API接口,更是为开发者提供了无限可能,让数据可视化变得更为简单、直观和生动。vvicAPI接口是一个高度灵活、易于使用的工具,旨在帮助开发者快速创建出美观、功能丰富的

web应用及微信小程序版本更新检测方案实践

背景:随着项目体量越来越大,用户群体越来越多,用户的声音也越来越明显;关于应用发版之后用户无感知,导致用户用的是仍然还是老版本功能,除非用户手动刷新,否则体验不到最新的功能;这样的体验非常不好,于是我们团队针对该问题给出了相应的解决方案来处理;技术栈:vue3+ts+vite+ant-design-vue1.web应用

视屏点播项目

项目背景大家应该在电脑上刷过视频吧,这个项目就是模拟一下我们刷视频的整个流程,我们要做的是一个类似B站的网页,这里面包含视频的上传修改和观看以及删除,注意我这个是一个简易版本的,在后面我会做一个升级,增加其他的功能.基本原理下面我们说一下我们项目的基本原理.我们这里做的是服务器客户端类型的项目.当客户端发起请求之后,我

PyTorch中的pyi檔案生成機制

PyTorch中的pyi檔案生成機制前言pyi檔由py生成pyi.in由pyi.in生成pyitorch/CMakeLists.txttools/pyi/gen_pyi.pygen_pyinative_functionsrand.names&rand.names_outrand.generator_with_names

Linux文件编程(lseek函数和stat函数)

文章目录前言一、lseek函数二、stat函数总结前言本篇文章来讲解lseek函数和stat函数,lseek函数主要用来设置文件偏移量,stat函数主要用来获取文件属性。一、lseek函数lseek函数用于在打开的文件中移动文件指针的位置。它可以用于设置文件的读写位置或查找特定位置的数据。函数原型如下:#include

Linux 系统下 CMake 示 例

CMake是一个开源的跨平台工具,可以构建、测试和打包软件。它具有如下特性:自动搜索可能需要的程序、库和头文件的能力;独立的构建目录(如build),可以安全清理;支持复杂的自定义命令(下载、生成各种文件);自定义配置可选组件;从简单的文本文件(CMakeLists.txt)自动生成工作区和项目的能力;在主流平台上自动

Linux之Shell进阶(变量和条件判定语句)

文章目录变量变量的含义变量的定义与使用(重点)只读变量接收用户输入删除变量条件判断语句变量变量的含义什么是量?量就是数据.什么是变量?数据可以发生改变就是变量。在一个脚本周期内,其值可以发生改变的量就是变量。什么叫做一个脚本周期?一个脚本周期我们可以简单的理解为当前的shell文件。变量是shell中不可或缺的一部分,

C#中的方法

引言在C#编程语言中,方法是一种封装了一系列可执行代码的重要构建块。通过方法,我们可以将代码逻辑进行模块化和复用,提高代码的可读性和可维护性。本文将深入探讨C#中的方法的定义、参数传递、返回值、重载、递归等方面的知识,并结合实际案例介绍方法的应用。方法的定义和调用:1.1方法是什么:方法是一个包含一组语句的代码块,用于

学习python和anaconda的经验

PYTHON1常用命令1.11.1注释Python注释多行的方法有以下三种:使用ctrl+/实现多行注释、在每一行的开头使用shift+#键、输入’‘’‘’'或者"“”“”",将要注释的代码插在中间1.2definit():函数区分两个函数:1.definit(self):这种形式在__init__方法中,只有一个se

热文推荐