概述
笔者在阅读一些postgres技术文档的时候,看到了一个对Postgres中,一些核心的概念、术语和名词的总结和释义,觉得有一些感想和收获,就觉得有必要著文进行记录和分享,就有了此文。
笔者认为,对于学习和使用postgres的技术人员而言,这些术语,特别是其背后的概念和理解,是非常重要的。不仅因为它涉及到数据库系统的基础理解和知识,特别对于Postgers这个数据库系统,笔者觉得它还是有很多独特和其他数据库系统(如Oracle、SQL Server、MySQL等)不太一样的地方,需要我们有相对正确的认知。
原本的材料是英文的,相关内容笔者按照理解和专业惯例进行了对应和翻译,并增加了一些觉得有必要讨论的内容,也可能有一些偏差和遗漏,读者如果觉得有问题欢迎提出来一起探讨。另外,在总结整理过程中,内容和材料越来越多,笔者只好将它们分为两个大的部分,本文就是上半部分,主要内容是通用数据库和SQL相关;第二部分才是Postgres相关的内容。
下面就基于这个框架,分章节进行分别叙述。
通用关系数据库
本章节中的概念和名词可能不是Postgres独有的,而是一种通用的关系数据库技术共有的、普遍的东西。
- RDBMS Relational Database Management System 关系型数据库管理系统
我们所熟知的关系数据库系统,其全称和学名其实是RDBMS,即关系数据库管理系统,它是一种用于管理关系型数据库的软件系统。RDBMS基于关系模型,它使用表格式的数据结构来组织和存储数据,并使用SQL语言来操作数据。
RDBMS的核心特性包括关系数据模型(Relational),SQL语言,数据完整和安全(用户权限、访问控制、数据加密、日志记录和恢复),事务模型(Transaction),网络访问(Network)等等。
- OLTP/OLAP 在线交易/在线分析
OLTP意为在线交易处理(Online Trasaction Processing),而OLAP则是在线分析处理(Online Analytical Processing),这两种是数据库系统的两种工作模式,它们可以用于不同类型和特点的业务类型和应用场景。
OLTP是在线事务处理,它用于处理日常业务操作,如订单处理、库存管理、银行交易等。OLTP系统的特点是数据量较大、并发访问频繁、对数据的安全、数据的一致完整性、事务实时性能等方面的要求较高。OLAP是在线分析处理,它用于数据分析和决策支持,如市场分析、销售预测、财务报表等。OLAP系统的特点是通常数据量更大、查询复杂、对查询和分析的灵活性要求更高。OLAP系统可能会采用专门的数据仓库或者相关技术,数据模型复杂、数据结构灵活,使用多维数据模型和预聚合技术来提高查询效率。
现代化的大型全能关系型数据库系统软件,这两种一般都是可以支持的,但可能不同的版本或者系统,它们在两种间的侧重和擅长是不同的。或者它们在不同的工作模式下,所需要的软硬件需求和系统配置,可能会有所差异。当然,对于非常专业或者要求更高的场景,可能使用更加专业的OLTP和OLAP系统,并且将两种工作和负载分离和独立开来。
- Table 数据库表
所有关系型数据库的一个核心功能,就是可以高效的存储和处理信息。它们通常使用一系列二维的表结构来实现这一点。一个表就可以承载一种类型的数据,这里的"类型"是一个面向对象的概念,就是一些信息或者数据,它们拥有类似的结构或者特性,差异在于这些特性的内容不同。所以本质上,要进行信息的存储,需要将信息进行分类,相同类型的信息,可以存储在一个表中。这个表的结构,就是它的列(Column),也称为字段(Field),可以对应着信息或者对象的属性;在这种结构之下,在这个表中,可以存储或者容纳多个相同类型的信息,就是它的行(Row),也称为记录(Record);通过扩展行,这样一个表,就可以容纳和处理多个相同结构的信息了。
- Column / Field 列/字段
如前面的描述,列就是构成表的结构,如果将表映射称为类型对象的集合,列就是对象的属性。
- Row / Record 行/记录
在数据表中,每一行,就是具有该结构的信息实体,或者用面向对象的方式来说,就是类的实例。
- Relation 关系
单个的表只能表达一种类型的信息或者数据,多个表构成的集合,才能表达更复杂多样的信息。而在真实的世界当中,不仅有各种各样的信息,信息之间可能还具有某些关联的方式,这就是关系。关系型数据库系统在设计和实现的时候,会充分考虑如何处理信息之间的关系,并且能够进行高效的表达和处理,这也是它们和传统的数据文件如Excel电子表格这种技术的一个非常显著的差异。
在关系数据库中,经常使用如PrimaryKey(主键)、ForeignKey(外键)、Join(关联查询)、等技术,来体现数据之间的关联关系和进行操作。从而能够在抽象层面上表达丰富复杂的数据和数据之间的关系,并且满足一些业务的逻辑约束,如唯一性、参照完整性等等。
常见的数据关联关系包括一对一、一对多和多对多等,在关系型数据库技术中,都有对应的实现范式。
- Join 关联
在关系型数据库中,体现数据关联关系的核心,就是Join操作,它在SQL中就是join子句和关键字。这个操作可以用于连接两个或者多个表中的数据行,连接的依据就是其指定的关联条件。
在标准关系数据库中,join操作包括inner join、left join、right join、outer join、cross join和self join等类型,它们分别可以应用于不同的数据关联逻辑表达需求当中,来构造所需要的结果集。
- Query 查询
就是在数据库中,检索和获取数据的过程。在一般的关系型数据库中的查询操作,遵循客户机/服务器的应用模式。即数据库客户端通过网络连接服务器系统,发出数据查询指令(一般就是查询SQL语句),服务端接收这个指令,进行相关处理,从数据库的数据中进行检索和组合,然后将查询结果作为响应发送给客户端。广义上的查询,就像这一一个过程,而狭义的查询,应当指关系数据库内部,接收并处理查询的请求和指令,执行查询,并返回结果的过程。
查询的输入一般就是一个select语句,查询的结果就是一个结果集,也称为记录集。查询操作中,可以控制和操作的项目包括表的关联、选择特定需要的字段、设置条件对结果过滤、限制结果集的大小(行数)、对结果集进行排序等等。
- RecordSet/ResultSet 记录集
一般将某个查询产生的结果,称为数据集。它看起来的结构和表一样,但显然它由查询方式来定义,是一个相对动态的结构和内容。
- Cursor 游标
数据库游标简单的理解就是一个在数据库结果集中的定位标记,通过操作游标,程序可以定位到结果集中的不同的行,从而达成在结果集中遍历的效果。实际上现在的数据库操作中,游标的使用已经不是很多了。笔者的理解,在早期的数据库软硬件系统中,相对而言数据处理能力比较差,就需要使用游标这种相对轻量化的机制,因为游标本身只是一个定位标识,定位后才需要处理所在的行,而且逻辑上一次只处理一行或者有限的行,系统资源占用比较低,所以游标是一种很重要的机制和技术。而现在的计算机系统容量和处理能力很强,一般情况下可以将结果集作为整体来处理,既方便又快速,游标技术的必要性就不是那么大了。当然,对于一些比较特别和特殊的应用场景(比如数据复制流),游标技术也是比较合适的,资深的开发者有必要对其理解和掌握。
- View 视图
在关系型数据库中,视图就是一个预定义查询的结果。视图的定义是一个查询语句,打开视图时,数据库执行这个查询,并返回查询结果作为视图的当前内容。
有很多场景适合使用视图而不是直接使用查询。比如视图可以定义查询的范围,包括查询条件、查询字段;可以给视图授权来进行数据访问控制;可以将视图作为基础进一步构造查询,数据库可以对视图查询进行优化和缓存,从而提高查询性能;可以使用视图的只读属性,来保护数据等等。
- Index 索引
索引,是所有关系型数据库,包括现在所有数据库系统的一项核心技术。它的作用基本上也只有一个:尽可能的提高数据检索和查询的性能,同时减少其需要付出的代价。索引的基本原理非常好理解,形象的比喻就是字典的目录,它可以通过内容的编码(比如笔画拼音),直接告知内容所在的页面。当然,在实际的计算机系统中的实现,需要考虑更多的因素,也是非常复杂的。在实际的数据库实现中,索引通常表现为一种特殊的数据结构和实际内容的映射关系,通过索引和查询条件,可以快速在庞大的数据库中,找到满足条件的数据和内容。
在标准数据库系统中,最常用的索引技术是B-Tree或者B+Tree。索引本质上也是一种规范化的内容映射和组织,就是将内容重新编码并更有效的组织起来,所以也有相关的文件和存储,也会占用相对应的磁盘空间。
- Constraints 约束
数据库中的约束是一种数据检查机制,用于确保数据的完整性、一致性和有效性。这些规则可以应用于表、列或整个数据库中的数据,以保证数据的质量和正确性。在有约束的情况下,如果操作的数据和约束规则冲突,就会产生错误,从而保证不会有错误的数据和信息可以写入数据库。
关系型数据库中的约束一般包括PrimaryKey、ForeignKey、Unique、Default、Check等。它们可以根据业务的需求,在数据处理过程中设置和使用。
- Primary Key 主键
主键用于唯一标识表中的每一行数据。主键必须是唯一的,并且不允许包含空值(NULL)。通过主键约束,可以确保每一行数据都可以唯一地被标识和访问。
主键可以基于单一的列,也可以基于多个列的组合,一般称为复合主键。
- Foreign Key 外键
外键约束用于建立表之间的关联关系。外键是表中的一个或多个列,它们关联了另一个表中的主键字段,就是说,它们的值只能包含这个表中的主键值,从而实现了表之间的确定性的引用关系和完整性,即在引用表中的值必须存在于被引用表的主键中。
使用外键,虽然可以在逻辑上,保证了两个表之间的严格关联关系,但也给数据维护造成了一些约束。比如删除主键表中的记录,必须同时删除引用表中的记录;再如插入记录到引用表时,必须保证对应外键的存在等等。
- Unique Constraint 唯一性约束
唯一性约束确保表中的某列或一组列中的值是唯一的,但允许空值(NULL)。与主键不同,唯一约束允许多个行具有相同的唯一值。
- Check Constraint 检查约束
检查约束是对字段中的数据进行条件限制,就是说只有满足条件的数据才能被插入或更新到表中。检查约束通常用于确保数据在业务方面的有效性和一致性,例如限制某个列中的值范围或格式等等。
- Default Constraint 默认约束
默认约束定义了当插入新行时,如果没有提供值,将会使用的默认值。这样可以确保表中的某列始终具有一个默认值。
- Aggregate 聚合函数
前面已经提到,所有的关系型数据库系统,多多少少都具备一定的OLAP的功能,就是数据分析的能力。其中,数据聚合,就是一个非常基础的数据分析的方式。
在数据库中,通常通过一系列数据聚合的函数,来实现聚合分析的能力。聚合函数是一类数据分析的方法和函数,它用于对一组数据执行计算,并返回单个结果,来表达这组数据的某个特性。如可以数据进行汇总(sum)、计数(count)、求平均值(avg)、最大值(max)、最小值(min)等操作。
聚合函数作为一种特殊的查询操作,它通常将select子句和group by结合使用。
- Window 窗口函数
聚合函数提供的功能是比较简单而单薄的。因此,在后续的发展中,数据库厂商还提出了窗口函数,来提高更强大和丰富的功能。
窗口函数(Window Function)是SQL中的一种强大功能,它允许您在同一查询中进行跨行计算。使用窗口函数可以对某些复杂的分析查询提供更清晰、更高效的解决方案。
比如,窗口函数不但能够计算数据分组的统计特性,还能够表达单个的记录与集合之间的关系,典型的就是当前记录的值,在记录分组中的排名,这是聚合函数无法实现的。
窗口函数也是一种查询语句,它通常将select和over(partition by...) 子句结合使用。
使用窗口函数,开发者可以大大的简化使用外部程序或者复杂的SQL(如自联机或者子查询)来执行很多常见的统计计算的情况,代码更加简洁,执行效率更高,并且易于维护。所以,熟悉和掌握使用窗口函数,是数据库开发人员的一项重要技能。
- Transaction 事务
事务是数据库系统的一个重要概念和特性。在数据库系统的工作过程中,事务是一个逻辑工作单元,它由一系列的数据库操作组成,这些操作要么全部成功,要么全部失败。这样,它就可以用于保证数据库操作的一致性和可靠性。
事务通常具有四个主要特性,也称为ACID。它们是:
- Atomicity 原子性
事务不可分割,要么全部成功,要么全部失败,如果失败,系统回滚到事务开始前的状态。
- Consistency 一致性
事务执行前后,数据库的状态必须保持一致。事务执行过程中,数据库的状态可能会发生变化,但是事务结束时,数据库的状态必须满足一致性约束。
- Isolation 隔离性
事务之间是隔离的,一个事务的执行不能被其他事务干扰。每个事务都有自己的工作空间,对其他事务是不可见的。
- Durability 持久性
事务一旦提交,对数据库的修改就是永久性的,即使发生系统故障也不会丢失。
- Trigger 触发器
人们在使用数据库系统的时候,有时候希望在操作的前后,做一些额外的工作,触发器就是为了这个场景而设计的。触发器是典型的事件驱动模式,但用户可以定义触发的模型和内容,来达成某些业务需求。比如触发器会在数据插入、更新或者删除时触发,来自动执行额外的各种操作。这些操作可能包括检查数据的格式或者规范性,插入、更新、删除关联数据,或者调用存储过程。
使用触发器,可以用于检查数据的规范性和完整性,记录数据操作的日志,跟踪数据变化,进行额外的操作安全检查,维护数据的一致和关联关系等等多个场景。
但需要注意触发器的应用场景和时机。对于大型的数据表或者记录集,触发器会增加很多额外的处理工作,可能会显著的对系统性能造成影响,所以在部署触发器之前,应该认真评估其需求和影响,或者寻求更好的技术方案,尽量降低触发器造成的不利影响。
- Explain 解释查询计划
数据库查询优化,是数据库系统应用过程中的一个非常重要的工作和内容。所以,一般的主流关系型数据库系统,都提供了相关查询计划评估的机制和指令,一般称为Explain,查询计划解释。
查询计划解释可以针对特定的查询语句进行解释和分析,帮助开发者了解数据库系统如何执行查询,包括提供相关的数据和信息,来帮助用户对查询或者数据库进行相应的修改和优化。
一般的解释查询计划可以帮助用户了解的信息包括:操作内容、执行顺序、成本估算、索引使用、统计信息等等。一个最常规的应用场景就是告知用户,某一个查询是否使用了索引,通常这个因素对查询性能的影响非常巨大;另一个典型的问题是不合理的查询结果集构造顺序,需要额外处理没有必要的数据。
但笔者感觉,现有的查询计划解释的使用对用户的要求比较高,它一般不会直接提供明确的结论和检验,只能提供数据和信息作为分析的依据,这样需要使用者具备相应的经验和能力。
- Logging 日志记录
虽然并不是一种强制的规范,但各家数据库系统,都不约而同的选择了日志记录技术,结合事务操作,来实现和确保数据完整性、一致性和安全性。
简单而言,就是在进行数据修改(开始事务)的时候,系统并不是直接修改数据文件,而是将事务执行的各种操作形成一系列操作的指令(日志),并记录在一个日志系统当中。只有当事务提交之后,数据库才会真正的将数据写入到数据存储文件当中,这个过程也称为"持久化"或者"落盘"。
使用日志有一些好处,首先它可以满足事务操作的要求,在提交之前,事务应该是隔离的;操作日志的效率和性能,要比直接操作数据存储要好;数据落盘的策略,可以平衡性能和可靠性,另外数据落盘也是批量处理,可以更高效。另外如果数据存储文件的磁盘系统发送错误,也可以使用日志来恢复和重做数据。最后,基于日志的系统操作,可以用于分布式系统中的状态和数据同步,这是很多数据库群集的工作基础。
SQL语言相关
除了关系数据模型之外,RDBMS系统的一个重要特性,就是使用SQL作为数据管理和操作的基础语言。本章节我们主要讨论和其相关的内容,例举和清理相关的概念和名词。而且这一内容,是所有类型的关系数据库的基础,和其品牌和版本没有直接关系。
- SQL
SQL的全称是结构化查询语言(Structured Query Language),它是一种标准化的用于管理和操作关系型数据库系统的编程语言。SQL标准由国际标准化组织(ISO)和美国国家标准协会(ANSI)共同制定,用于规范其语法和功能。
和所有标准化技术一样,SQL标准也有其发展和演进的过程。最早的SQL版本是SQL-86,它定义了SQL的最基本的语法和框架;现在最新的版本是SQL-2016。作为一般的基于特定数据库系统的开发者,我们通常不是特别关心这个标准和规范,但其实各个数据库系统的发展,多多少少受到这个标准的影响。虽然其实这个标准并没有强制性,但各个数据库系统厂商和开发团队,基于兼容性和互操作的考虑,都在不同程度上,尽量遵循这一标准和规范。在这个方面,PG的表现是比较好的,它对标准SQL的支持,一直是实现的比较完善和充分的。
和一般的标准计算机编程语言如C、Java不同,SQL在逻辑上是一种更高级的"指令性"的编程语言系统。传统的编程语言,本质上都是过程性语言,就是需要人类模拟计算机处理的过程和思维方式,来建构数据和信息处理的方式和过程,来达成某种应用需求。在这个意义上,如C这种所谓的"高级"编程语言,其实和如汇编这种"底层"的编程语言,其实只是相对能够让人类更容易理解和使用,并没有本质的区别。SQL则不同,它才是真正的"高级"语言,整体的编程过程和逻辑,就是人类组织思考和使用语言表达的过程。
当然在现阶段,由于处理技术的限制,负责语法解析的程序(关系型数据库的核心组件),还不能完全的直接使用和处理人类的一般语言,必须要对其语法进行规范、限制和抽象,这应该就是所谓的"结构化"。这就是我们现在在SQL语言中看到的必须使用某种语法规则和结构的结果。
不过笔者觉得由于GPT技术的快速发展,这个状况可能会再次有所发展,基于AGI技术加持和改进的数据库系统,可能很快就能接收和理解真正的人类的自然语言,你只需要描述需求,它就可以构造适合的SQL语言,甚至其实可能不再需要SQL,数据库系统可以直接理解人类的自然语言,并根据其意图来正确的执行相关的数据指令,进行数据操作或者获取查询结果了,让我们拭目以待。
根据目的和功能的不同,SQL语言体系,还可以进一步细化为DDL、DML、TCL等部分和类型。
- DDL Data Definition Language 数据定义语言
关系型数据库基本理念就是,使用结构化的方式来对数据进行存储,以方便后续的高效管理和操作。所以在所有的数据记录和操作之前,需要先定义各种相关的数据结构,这些操作被称为数据定义,并使用一套数据定义语言配套操作。它们通常围绕着表、字段、索引等对象使用。
常见的DDL语句包括Create(创建对象如表、索引、视图等)、Alter(修改数据库对象,如表中的字段等)、Drop(删除数据库对象)、Truncate(截断,清除数据但保留表结构)、Rename(更名)、Comment(添加注释信息)等等。
- DML Data Manipulation Language 数据操作语言
DML用于对数据库中的数据进行操作。所有的数据操作,都可以被抽象称为查询(获取)、插入(创建/增加)、更新(修改)、删除四种类型,所以DML的主要语句就是Select、Insert、Update和Delete四种,它们操作的数据实体,就是数据库中的表(视图)和行。其他辅助和扩展的语句可能还包括Merge(合并)、Lock(锁定)、Call(调用)、Explain Plan(执行机会解释)等。
- DCL Data Control Language 数据库控制语言
DCL用于对数据的操作和访问进行权限控制,它主要包括 GRANT(授权)、REVOKE(撤销授权)等语句。在关系数据库中,DCL是一个很重要的数据安全特性和机制。
- TCL Trancation Controll Lanuage 事务控制语言
TCL用于对事务进行管理、操作和控制。其目的是确保在并发操作的情况下,数据的一致性和完整性。一般的TCL包括以下几个概念和语句:BEGIN(开始事务)、 COMMIT(提交)、ROLLBACK(回滚)、SET TRANSACTION(设置隔离级别)、 SAVEPOINT(创建保存点)、
在一个相对完整的多步骤操作中,TCL通常和DML结合使用。如可以使用BEGIN TRANSACTION语句开始一个事务,然后使用DML语句对数据进行操作,最后使用COMMIT语句提交事务,出现问题或者错误,也使用ROLLBACK语句回滚事务。
- Statment SQL语句和子句
在SQL的世界中,所有的程序,都是使用SQL语句来表达的。虽然看起来像是人类的自然语言,但现在的数据库系统还不够智能,只能使用严格规范的语法和结构,称为SQL语句。每个完整的SQL语句,都有一定的关键字、顺序规范和可选部分组成。很多可选部分也称为SQL子句,如用于指定查询条件的Where子句,用于排序的Order By子句和用于窗口函数的Over子句等等。熟悉了这些概念、结构和规则,才能够很好的编写和使用SQL语句来进行编程和数据处理。
- Batch 批处理
有些关系数据库系统和客户端支持一次执行多个SQL语句,作为语句块提交给服务器执行,通常被称为批处理。批处理相比单独提交SQL语句的方式,服务器可以进行优化和处理,一般性能会比循环单个处理高。并且批处理还可以支持事务,来满足一些批处理过程中数据完整性和一致性的要求。
- Stored Procedure 存储过程
存储过程这个名词,在不同的数据库中可能会稍有不同,实现细节也可能有一些差异,比如PG称为function函数,使用PL/pgsql语言,但其基本概念是相同的。
在数据库中,使用SQL语言其实有一些限制,比如执行的语句,都是被作为整体来对待的,缺乏中间变量的处理机制,无法进行流程控制等等,包括批处理方式也不能很好的应对。针对这个情况,各家数据库系统,都提供了一种扩展机制,即开发者可以编写一段程序,以标准SQL为基础,来组合执行更复杂的数据处理。这个程序直接存储在数据库系统中,可以使用SQL类似的方式来进行调用,这一就大大扩展了数据库在内部执行复杂处理的能力。
存储过程存储在数据库内部,可以为不同的客户端来调用,提高了业务代码的可重用性和业务逻辑封装。一般数据库会提供存储过程的编译和优化机制,使存储过程的执行效率高于普通外部SQL调用。存储过程同样支持事务和权限控制,保证数据处理的完整性和安全性。所以存储过程是一个非常重要和必要的数据库系统能力扩展机制。
小结
本文包括后续文章,讨论了Postgres包括通用关系型数据库中的一些常见但是重要的名词和概念,并尽量的基于笔者的认知和理解,简单清晰的进行了叙述和解释,希望对于开发者对于这些内容有新的视角和理解,并帮助开发者在工作中正确的予以应用。
由于篇幅的限制,全文被分为两个部分,本文作为第一部分,探讨了通用的关系数据库和SQL相关的内容,后续章节将会讨论Postgres相关的内容。