PostgreSQL 内部术语
2023.10.21 03:21浏览量:64简介:本文是关于开发人员在谈论 PostgreSQL 时使用的术语的一个非官方的或许还不太完整的介绍。
Craig Kerstiens 发表了一篇关于 Postgres 术语的文章,涵盖了一些初学者会遇到的基础性信息。有趣的是,我们很快就习惯了行话,甚至忘记了我们正在使用它。它成为秘密接头的一部分,是我们向部落其他成员发出的信号,表明我们是这个团体的一员。
当第一次参加 Postgres 大会时,听到 Postgres 核心成员的对话,我瞬间迷茫:他们在说什么?
后来我发现,他们说的词和短语,大部分都来自 Postgres 的代码,而 Postgres 代码使用它们是因为它们是关系模型的一部分,而关系模型是支撑所有关系数据库的理论体系结构。
本文是关于开发人员在谈论 Postgres 时使用的术语的一个非官方的或许还不太完整的介绍。
Tuple(元组)
tuple 是 Postgres 的一个基本的构建模块,故而它会经常在开发人员的谈论中出现。
tuple 即大部分人理解的表中的行。它由一些列组成,每一列则由列名、列值和数据类型组成。内部格式可参考表行布局。
我们还会经常听到 “Tuple set”,即为行集,也就是常说的表;或者,是类似于表的对象。稍后,我们还可以看到其他表示类似于表的对象的特殊词汇。
Record(记录)与 Row(行)
Record 与 Row 是对 Tuple 的另一种说法,但与 Tuple 不同的是,record 与 row 一般用户 SQL 查询中。
record 关键字一般用于数据库服务端返回复合数据类型的函数的返回类型。
CREATE FUNCTION onerow(pk integer)
RETURNS record AS
$$
SELECT * FROM mytable WHERE mytable.pk = pk
$$
LANGUAGE 'sql';
row 关键字用于在 SQL 中构建复合数据类型。
INSERT INTO on_hand VALUES (ROW('fuzzy dice', 42, 1.99), 1000);
Array(数组)
数组即为具有相同数据类型的值的列表。以下为整数数组的示例:
SELECT ARRAY[1,2,3,4];
数组还可以是多维的:
SELECT ARRAY[[1,2,3],[4,5,6]];
而且,数组不仅仅限于 Postgres 内置的数据类型,还可以用于自定义的类型:
CREATE TYPE person AS (name text, age integer);
SELECT ('Peter',45)::person;
SELECT ARRAY[('Peter',45),('Paul',35)]::person[];
Relation(关系)
relation 即为行的集合。单行为一元的关系,N行未N元的关系。
不过,通常来说,我们指的关系为“表”。
每个表均是关系,但反之不然。
视图也是关系的一种。
所以,实际上,关系为查询的结果。查询结果即为行集,其即为关系。即使查询的中间步骤,也可以看为一个关系。
而使用连接条件关联两张表得到的查询结果,也是一个关系!
可通过查看 pg_class 系统表来直观感受下数据库中的关系:
SELECT relname, relkind FROM pg_class;
该查询列出了 Postgres 中的所有关系。其中,relkind 为 r 的是表。结果中还包含索引、视图、序列、物化视图和外部表。
Target List(目标列表)和 Restrictions(限制条件)
随着对 Postgres 的深入了解,会发现一些不知道其名称的东西。例如,查询语句中,介于 SELECT 与 FROM 之间的叫什么?WHERE 之后的叫什么?
SELECT <此为目标列表>
FROM mytable
WHERE <此为限制条件>
Schema(模式)
模式类似于数据库中的一个文件夹。但实际上,Postgres 内部使用命名空间(namespace)指代模式(schema)。可通过查询 pg_namespace 表查看数据库中的所有模式:
SELECT * FROM pg_namespace;
这还不是全部。当我第一次听到“模式”这个词时,我感到非常困惑,因为在我看来,“模式”是“数据库中表定义的集合”。因此,“应用程序模式”可能是数据库中用于支持特定软件应用程序的所有表。
因此,“模式”(SQL 层面来说)是一个文件夹,可以在其中放置数据库对象(如表、函数等),而在 Postgres 中,也被称为“命名空间”,有时(对应用程序开发人员来说)是一个或多个表的定义。
Page(页)
时间再久一些,就会经常听到 pages 这个词了。
万幸,pages 是数据库内部的实现细节,对最终用户来说,是透明的。
而数据库管理员则需要对 pages 有一定的理解,因为有些优化参数会涉及到 pages。页面的具体内部格式,可参见数据库页面布局。
在磁盘层面,数据库表以文件形式存在,一个文件一个表(实际上,当表足够大的时候,会包含多个文件,此处暂时忽略这种情形)。
如果表中的每行数据都紧凑的装载到一个文件中,那么当数据变化的时候,数据库该如何变更它呢?
例如,将名字从 Paul 变更为 Paul the Great,如果行紧凑存储,那么就需要扩展表,然后将Paul后的所有数据后移,以扩大空间。毫无效率可言!
这就有了页的概念。数据库在内部将表文件划分为规则间隔的“页”,并仅用元组填充每一页的部分(对此有另一个术语,即“填充因子”),而不是使用一个紧密填充的数据文件。现在,当数据库需要更新一个元组(可能要添加更多数据)时,只需要重写相关的页,而文件的其余部分则可以保持不变。
“页”在许多方面都是底层数据库引擎的基本单元。在编写SQL时看不到它,但是像“页缓存”(一块RAM,用于高速访问频繁读取的页)和“随机页成本”(一个表示在文件内随机访问所耗成本的调优参数)等证明了“页”在数据库系统设计中的中心地位。PostgreSQL页固定为8192字节。这也是WAL等的内存“块”的默认大小。有些块大小可以调整;但页不可以。
Toast
“Are those objects toasted?”
他们在说什么?是要把数据库对象烤了吃掉么?
而实际上,Toast 在 Postgres 中,是 “The Oversized-Attribute Storage Technique” 的缩写,表示超限属性存储技术。
还记得 Postgres 中页的存储构建方式么?是的,它们是固定大小的 8kb,那么如果存储超过 8kb 的记录,会发生什么呢?那我们就遇到了超限属性的问题。
与页类似,Toast 也是对最终用户透明的技术。当输入的属性超过页的大小时,Postgres 会将其切分为小块以适应页的大小,并将它们放到一个与主表关联的 Toast 表中。
-- Find the toast table associated with a user visible table
SELECT a.relname, b.relname AS toast_relname
FROM pg_class a
JOIN pg_class b
ON a.reltoastrelid = b.oid
WHERE a.relname = 'mytablename';
然后,当查询涉及到该元组时,数据库会检索 Toast 表中的数据,并将其合并后返回。
故而,检索被 Toast 的数据比检索普通的数据,需要消耗更多的时间。
结论
本文仅含部分专业术语,期望不久的将来,可发布更多的专业术语释义。
发表评论
登录后可评论,请前往 登录 或 注册