本文是《Postgres主要概念和名词简释》的第二部分。主要侧重于PostgreSQL系统相关的内容。
全文的上篇在这里: 《Postgres主要概念和名词简释-上》 juejin.cn/spost/73564...
PostgreSQL系统
- PostgreSQL
先说说这个产品名称是怎么来的,因为英文中并没有简单的一个这样的词。这个词,其实是三个词构成和衍生而来的。gres其实是ingres(Interactive Graphics And Retrieval System,交互式图形和检索系统),这是一个古早的起源于UC Berkeley的数据库技术的研究项目。当然,这个项目早在1985年就关闭了,但在这个项目的基础之上,诞生了关系型数据库系统的技术和后续产品,这里,Post就是后续的意思。SQL就是它作为数据库系统所使用的语言和技术。简化而言,PostgreSQL就是"后ingres+SQL"系统的意思。从这个角度,PG在关系数据库系统中,还真的是历史悠久,根正苗红啊。
- Version 版本
虽然诞生的非常早,发展过程也比较上,但Postgres在系统发展和活跃方面,笔者感觉是做的非常好的。在产品发展的过程中,PG遵循的是"小步快跑"的策略,完全是典型的互联网技术和产品演进的方式。这可能是它和Oracle或者MS SQL等产品以企业应用需求主导的产品发展相对,而PG主要是基于互联网和开源社区发展的模式不同而确定的。
从其版本发展的过程,我们大致可以看到,由于产品已经相对稳定成熟,基本上Postgres会在每年的9或10月份,发布一个大的版本,并持续大约5年的产品生命周期,在生命周期中,稳定的开发和发布中间版本。比如,当前的最新版本是16.2(2024年2月8日发布),版本16是在2023年9月14日初始发布的,计划延续到2028年11月。
- Database Cluster 数据库群集
PG中的cluster概念好像和其他数据库系统稍有不同,它并不是指数据库服务器硬件的群集,而是指的是数据系统中,数据库的集合,即一个相对逻辑化和软件化的概念。
- Database 数据库
PG中,数据库是架构(Schema)的集合。一个数据库可以包括多个架构。
- Schema 架构
Schema是一些对象的集合,这些对象包括表(Table)、视图(View)、方法(function)等等。Schema的目的是为在数据库和数据库对象之间,提供一个逻辑的命名空间,方便数据库对象的组织和权限的控制。在PG中,默认的Schema是Public,也是默认的数据库对象引用和搜索的路径,如果在数据库中,没有其他的Schema,则可以在书写时省略(但SQL解释器在实际执行时,会自动添加这个Schema)。
- Relation 关系
在PG中,将数据库表和索引对象,也称为Relation。
- Table 表
同所有关系型数据库表。
- Tuple 元组
这个和一般的说法有点差异,PG中的Tuple,其实就是行(Row)或者记录(Record)。使用元组,可能主要为了体现PG在数据库中,可以支持更加丰富和灵活的数据类型。
- Attribute 属性
就是表中的列(Column),或者字段(Field)。笔者认为,之所以有这种不同的称为,是因为PG实际上是一种"混合"类似的数据库系统,它可以很好的支持自定义的数据结构和对象,并不只是简单的行、列和表的组织方式。
- Instance 实例
PG中,运行的数据库服务程序的逻辑概念。因为在同一台服务器软硬件环境中,可以运行多个这样的程序,它们具有相同的原始和程序代码,但可以被启动多次,对应不同的数据库数据集合和网络侦听端口,称为实例。
- Tablespace 表空间
PG表空间,笔者理解是指数据库表/索引这个逻辑实体,和数据库程序所在操作系统的文件中,文件夹和文件等的映射关系,因为表和索引需要实际的占用磁盘空间和存储。除此之外,表空间还提供了某种灵活性,可以让数据库管理者,可以将数据库中的对象,合理规划和分布在不同的磁盘或者文件系统上,来获得更好的性能表现或者可用性。另外,直接操作表空间文件,可以方便快速的进行系统备份恢复等大规模、整体性的数据操作,从而简化这一类的操作和管理。
- MaterializedView (MV) 实体化视图
MV顾名思义,就是将视图的结果持久化存储下来,本质上就是查询数据的缓存。从使用者角度而言,这个MV、视图和表的查询方式都是一样的。但由于对查询结果进行了缓存,并且MV也支持索引(MV上的),MV一般情况下可以提供更好的查询性能。
作为一种缓存机制,MV的核心和要点是数据刷新的时机和效率,需要尽量保持数据的时效性,同时又不能明显的影响系统的性能。PG的MV支持手动刷新、定期刷新、自动(数据变化触发)刷新和增量刷新等特性,它们都有一些优势和限制,包括MV的应用在内,都需要适当的选择和评估。
- Index 索引
除了常见的BTree之外,PG还支持更多的索引类型包括HASH、GiST、SP-GiSP、GIN、BRIN等,它们都有不同的特点,适合不同的数据场景。
另外,PG还支持计算值的索引,可以提供更灵活方便的开发和应用选项。
- Partition 分区
对于数据量非常大的数据表,使用分区是提高操作和查询效率的一个常见和有效的策略。简单而言,分区就是将一个大型的数据表,按照某种规则,分割成为更小的、独立的子表(分区)。显然,针对特定分区中的数据,相比原来的大型单一数据表,分区技术可以显著的减小需要处理的数据规模,从而提高操作和查询性能。此外,使用分区,还可以提高数据维护的灵活性,如数据的备份和恢复都会方便很多。
当然,分区技术会带来一定复杂性,所以分区的技术实现就非常重要,尽量不改变原有的操作方式和数据规则。分区功能的成熟的标志,是提高了完整的分区设置相关的语句和功能,支持各种分区类型包括范围、类型和Hash等,还能够方便的对分区进行挑战,并且能够在数据操作和查询过程中,自动的处理分区策略,也能够透明的处理如索引这样的机制,使开发和处理数据的工作基本上和单个的表没有太大差异。
PG原来对分区的支持比较薄弱,需要一些额外的设置和操作,只有到最近几个版本,才逐渐的完善了对数据表分区的支持,达到了一个比较稳定和好用的状态。
- Sequences 序列
PG中,Sequence是用于生成数字序列的对象。它用于自动生成主键、唯一标识符、或者不重复信息的应用场景。和程序化的外部实现相比,序列显然能够提供更好的性能和透明性。
- Datatype 数据类型
在PG中,可以自己定义数据对象的结构,称为自定义数据类型。定义数据类型,可以基于业务需求,限制数据的内容结构和操作,或者方便将数据作为整体来进行处理。
- Enum 枚举
枚举是一个计算机数据结构和类型的概念,枚举类型是一个包含静态值的有序集合的数据类型。它的作用主要是限制赋值和使用,很多业务有这样的需求,比如一周中的七天,或者一个订单的有限的状态等。使用枚举,就只能使用枚举集合中的值,否则将会出现错误。此外,枚举数值表面上可能是个字符串,但那主要是为了方便标识和使用,实际在计算机系统中的操作,它可能就是一个简单的整数。
PG支持枚举,可以在定义数据类型时,指定当前的类型为枚举,并且设置枚举值。
- ARRAY 数组
笔者对于其他关系型数据库的使用经验不是特别多,所以不知道关于这一点在其他数据库中的情况是怎样的。仅讨论Postgres的情况。PG可以支持将数组作为字段或者列,而且支持丰富的数据类型。这个特性,在很多应用场景中是非常有用的,比如可以直接存储一个列表,可能就不需要额外的字典数据表来做关联操作了。
能够存储数组化的数据,只是一个基础。更重要的是无论是作为整体,还是个体,系统应该能够支持对数组和数组中的元素的方便而直观的处理,在这方面,笔者感觉PG的实现是比较不错的。它提供了很多相关的内置函数和操作符来支持这些操作,比如索引访问、数组的合并和拆分、数组元素修改、长度计算、字符串聚合和转换等等,也支持数组元素作为查询和过滤条件,功能是比较丰富和完善的。
- JSON/JSONB
PG从很早就提供了对JSON格式的原生支持。因为实际上,JSON是互联网应用开发的事实上的标准数据格式。对JSON的支持,是作为数据存储基础技术对互联网应用支撑的一个重要的特性。
PG对于JSON的支持也是由一个比较长的过程,笔者认为到现在已经算是比较完善和丰富了。比如它提供了扩展了很多操作符号和函数,来方便的对JSON进行表达和处理,来满足如对象属性引用、对象合并、对象属性修改等实际应用中很普通的需求。
此外,针对原生JSON对象只能表达成为字符串的形式,在数据库中的存储和处理效率不高的问题,PG还开发和提供了JSONB的格式,就是可以将JSON编码成为二进制的形式来进行存储和处理,从而提高存储和处理的效率。在日常应用开发中,一般实际使用的就是这个格式,对于开发和使用者而言,方式和标准JSON并没有明显的差异。
- hstore
PostgreSQL中的hstore,实际上是一种在关系型数据库中,存储和处理键-值类型数据的技术。在PG数据表中,可以定义一个字段是hstore的类型,然后就可以使用键值方式来存储和处理更灵活的数据结构和内容了。特别适合于很多数据结构不固定,不规则,但又可以抽象成为属性化的数据。
笔者觉得,hstore这个技术,原本可能是基于应对或者实现如MongoDB这种对象性数据库而产生的。实际上我们也可以借助hstore,将postgres改造成为对象数据库或者混合数据库。但笔者又发现,可能是引入JSON技术的原因,在现在应用hstore的技术的必要性,好像也不是特别大,很多特性和功能,好像都是JSON可以替代和实现的。
需要注意,在技术上,hstore是postgres的一个扩展,虽然是PG安装时就原生附带的,但实际应用之前,还是需要先将其作为扩展模块安装到当前数据库中。
- Function 方法
所有的数据库系统,除了基本功能之外,都需要在数据库内部提供一定的扩展能力和灵活性,让数据库用户可以有机会自己编写合适的代码,来进行数据的处理。这样机制的通用称为就是前面提到的存储过程,在PG中通常被称为方法或者函数。
和Oracle不同,PG不区分存储过程和函数,统一称为函数(方法)。 PG的方法,可以支持多种语言,包括SQL、pgSQL、Python和Perl等等。很多PG的扩展,也是通过扩展功能结合定义方法来实现的。
- Procedural Language 过程语言
在PG中,除了在系统级别的C语言,以及在应用级别的SQL之外,通常使用其支持的几种其他语言来编写用户自定义的函数,这些语言通常被称为过程语言(Procedural Language)。需要注意,一般情况下,数据库服务器本身并没有能力解释和运行这些过程语言代码,而是需要一个所谓的PL语言引擎,它来负责对应语言的语法解析和执行工作。这个语言引擎,在PG中也是一系列标准的C函数,它可以被编译到PG执行环境中,并且可以按需加载和运行。
在PostgreSQL的标准发布中有四种过程语言可用,包括PL/pgSQL、 PL/TCL、 PL/Perl 和 PL/Python。作为一种高度可扩展的系统,PG也支持通过扩展的方式,来支持更多种的编程语言,甚至自定义语言。
- PL/pgSQL
PL/pgSQL是PG中,编写自定义函数最常用的语言,应该也是PG原生内置的官方PL语言。从名词上我们就可以感觉到,pgSQL是以SQL作为一个基础和核心,构造的一个过程性语言。笔者理解,这是因为SQL语言本身作为一种指令性语言,缺乏很多常规过程性处理所需要的特性,比如变量定义、变量操作、记录遍历、控制结构、参数处理等等,pgSQl就是基于这些需求,对SQL进行了扩展,并且让它能够在PG环境中,通过构造函数来运行比单个SQL更复杂的流程化操作。
除了支持流程化处理之外,在业务系统中使用pgSQL或者任意类型的PL,还有助于将一些数据处理的功能模块封装起来,暴露给外部的就是简单的参数化函数调用,有助于系统的模块化和简化开发和维护。
- User 用户
在所有的数据库系统中,用户的概念,就是用于标识当前已经登录系统并正在进行操作的人。用户一般可以给关联到一个具体的人,或者作为这个人的代理来执行相关的操作。对于管理、授权和审计而言,都可以通过用户账号追溯到一个具体的自然人,从而达成某种社会性管理需求的目的。
- Role 角色
对于熟知一般数据库系统的开发者而言,PG中的角色的概念有点奇怪。一般而言,角色本质上是一个权限组合的逻辑实体,它不能独立的工作(登录和操作),也不需要指定凭据(密码),而是需要和某个用户关联,然后这个用户就可以应用这个角色的权限。
但在PG中,用户只是一个特殊的角色,主要差异在于它可以用于登录系统。甚至创建角色时,可以通过指定LOGIN选项,让角色也可以登录系统。从这点来看,PG中用户和角色是相同的概念,只是名词不同而已。
- CTE Common Table Express 公共表表达式
Postgres支持CTE,这是一种临时的查询结果集,你可以对其进行命名,然后在SQL语句中重复使用。PG的CTE使用With子句实现。CTE本质上是一种子查询,但通过合理的语法组织,开发者可以使SQL语句的结构和处理的过程和思路更加清晰简单。并且让人能够更容易理解和维护。
- MVCC Multi-Version Concurrency Control 多版本并发控制
对于任何一个需要为多个用户提供服务,并且对同一份数据进行同时读写操作的数据库系统,并发控制也是其核心功能之一。 PG使用MVCC来实现和管理并发访问控制,并且确保在此过程中,数据不会发生丢失或者不一致的状况。
简单而言,MVCC的核心特性就是,修改数据时,PG不会直接操作原始数据,而是创建一个新的数据版本;后续的事务操作,会基于事务前的数据形成的"快照",从而实现了事务隔离;最后事务结束时,用户就可以选择合适的时机,对不再需要的旧版本数进行清理从而并释放存储空间,保持数据库系统的健康和稳定。这个清理可以是自动的(AutoVacuum),也可以通过指令Vacuum来执行。
通过精心的设计和实现,PG的MVCC的优点包括可以提高系统并发性能、减少了锁竞争和死锁的可能性、提高事务的可重复性和隔离性等。
- Vacuum 数据清理
Vacuum的原意是"真空",也有吸尘器的意思。在PG中Vacuum就是无效数据清理的操作。实际上PG的Vaccum有很多选项,如FULL、FREEZE、ANALYZE等等,适合于不同的应用场景,开发者可以根据实际情况和需求选择。此外,Vacuum的执行,特别是FULL选项,可能会显著的增加IO和磁盘操作,从而影响系统服务能力,需要认真评估其执行的场景和时机。
PG还提供了AutoVacuum的选项,是一种自动化的数据库维护机制。这个选项开启之后,默认情况下,系统会每隔1分钟就会启动对系统的检查,根据修改数据的情况,决定启动真实的回收操作。从而实现了数据库的自我健康维护。
- Analyze 分析
Postgres为了优化查询和提高查询的效率,提供了Analyze命令,这个命令可以用于分析数据表中的数据分布方式和特性,如数据分布、基数(不同值的数量)、最小值、最大值等,并生成对应统计信息记录在系统状态信息表中。这个统计结果,可以被解释计划或者查询优化器来评估不同执行计划的成本,帮助用户选择最佳的方式来执行查询。用户可以通过合理的选择分析操作的时机,或者定期执行分析命令,来使系统数据统计信息保持在一个更新的状态,从而提供比较好的查询性能。
- Sample 采样
对于非常大的数据表进行分析,进行全表的数据分析的代价是比较高昂的。为此,Postgres在进行分析的时候,提供了基于采样的收集统计信息的选项,它基于统计学的原理,对表格中的数据进行随机抽样,来获得相关的统计信息。显然,这样的方式,可以大大减少数据分析的时间和成本,但确定是估计结果会存在一定的误差。所以,Postgres可以在采样时设置采样百分比,让用户可以在性能、时间和准确度等方面进行取舍和平衡。
- WAL Write-Ahead Logging 预写式日志
前面已经提到,在主流的关系型数据库系统中,都使用日志,作为保证事务持久性和可恢复的机制,Postgres也不例外。PG的日志技术被称为WAL,它明确的表达了其实现的基本原理,就是在数据真实的写入数据库之前,会预先写入日志文件。相对的,Oracle的日志技术通常叫做"Redo Log",其实,它们在基本概念和原理是类似的,只有实现细节上有细微的差异。
- Extension 扩展
Extension,是Postgres区别于其他的RDNMS,并且非常具有自我特色的特性。PostgreSQL的扩展机制非常强大,提供了非常高的可定制性和灵活性,用户可以在不修改PG核心代码的情况下,轻松地添加所需的功能,从而实现定制化的数据库环境。这些扩展内容可以包括如数据类型、函数、索引类型、外部工具、外部语言等等。同时,作为全球领先的开源数据库系统,它拥有一个开放、活跃和高水平的开放社区体系。很多扩展,都是由社区和第三方贡献的。
PG对扩展的使用也是一种按需插拔的模式,非常方便和灵活。在笔者日常使用的扩展中,常见的扩展包括plpgsql(PL语言)、pgcrypto(密码学库)等;其他知名的扩展还包括pggis、pg_stat_staements、postgres_fdw、uuid_ossp、pg_cron、timescaledb、pgvector等等。
- psql
psql,笔者理解,实际上就是postgres官方的cli客户端工具软件。使用psql,用户可以连接本地或者网络上的PG数据库实例,使用用户账号来进行登录,然后进行后续的数据操作。默认情况下,安装PG服务器软件,就会在操作系统中自动安装psql;但如果要在管理客户端上安装psql,需要单独安装PostgreSQL Client软件包,它会带有psql工具和命令。
psql有两种运行模式,交互模式和命令模式。交互模式在数据库连接后可以进入一种特殊的命令行模式,就是数据库操作的上下文命令行界面,在其中可以直接执行各种SQL和其他指令;命令模式是可以直接执行某个SQL指令,或者SQL指令脚本文件,特别适合于一些数据库管理和数据操作自动化的应用场景。
- pgadmin
和Oracle(SQL Developer)、MSSQL(SQL Server Management Studio)甚至MySQL(MySQL Workbench)不同,看起来Postgres是没有官方正式的GUI客户端管理工具的。一个官方推荐的管理工具,应该算是一个社区开发的软件,名为pgadmin, 算是一个半官方的选择吧。有趣的是,pgadmin并不是一个正常的GUI工具,而是一个Web工具,可以在安装后,通过本地的Web服务,来提供操作和功能。从它的产品介绍( www.pgadmin.org/ )来看,虽然是个页面工具,但它提供的功能也是非常丰富强大的,有兴趣的读者可以自行安装体验。
虽然缺乏官方原生的客户端工具,但很多数据库工具系统都可以很好的支持Postgres系统。比如笔者现在使用的DBeaver Community Edition、包括使用更为广泛的Navacat,甚至很多开发工具都集成了数据管理的功能或者插件,开发者可以根据自己的喜好,选择使用。
小结
本文是文章《Postgres主要概念和名词简释》的下半部分。讨论了SQL语言和Postges作为关系型数据库中的一些常见但是重要的名词和概念,并尽量的基于笔者的认知和理解,简单清晰的进行了叙述和解释,希望对于开发者对于这些内容有新的视角和理解,并帮助在工作中正确的区分和应用。