\dtS, \dS
关系型数据库(RDBMS)有两个基本的问题: 1.对象如何被表示? 2.系统如何找到它们?
每一种对象由系统目录中的一行或多行表示
- pg_databse: 一行代表一个数据库
oid, datname, datdba, datacl[], encoding, ... - pg_namespace: 一行代表一个schema
oid, nspname, nspowner, nspacl[] - pg_tablespace: 一行代表一个表空间
oid, spcname, spcowner, spcacl[]
对于其他更具体的对象也是如此:
pg_class: 其中的每一行代表一个关系 (Relation),这包括了表、视图、索引、序列等。这是最核心的目录之一。pg_attribute: 其中的每一行代表一个列 (Attribute),并指向它所属的表。pg_proc: 其中的每一行代表一个函数或存储过程。pg_constraint: 其中的每一行代表一个约束。
Role=Privileges/Grantor jas=arwdRxt/jas,fred=r/jas,joe=rwad/jas
Role(角色/被授权者): 指的是权限被授予了谁。如果这个部分是空的,则代表授予了PUBLIC(即所有角色)。Privileges(权限): 指授予了哪些具体的操作权限。它由一系列单字符代码组成。Grantor(授权者): 指这个权限是由谁授予的。a(增),r(读),w(改),d(删),R(规则),x(引用),t(触发器)
关键点:当你执行 CREATE TABLE my_table ... 时,PostgreSQL 实际上就是在 pg_class 表里插入了一行来记录 my_table 的存在,并在 pg_attribute 表里插入了多行来记录它的所有列。每个对象都有一个独一无二的 OID (Object Identifier),作为它在整个数据库系统中的内部“身份证号”。
Global db: catalog tables defining: databases, users
Local db: schemas, tables, attributes, functions, types
一个表的所有信息不都只在一个表里,pg_class是主入口,记录主要信息,pg_attribute记录详细信息,pg_constraint记录数据的约束规则。
pg_class除了普通表,还有
- Views (视图): 本质是一个存储起来的查询,但可以像表一样被查询。
- Composite (tuple) types (复合类型): 用户自定义的一种数据类型,其结构就像一个表的行结构。实际上,每创建一个表,PostgreSQL 都会自动为其创建一个同名的复合类型。
- Sequences (序列): 用于生成唯一序列号的对象,常用于自增主键。
- Indexes (索引): 用于加速查询的数据结构,它本身也有自己的物理存储,可以被看作一种特殊的关系。
- 其他特殊对象: 如物化视图(Materialized Views)、外部表(Foreign Tables)等。
pg_class 表中一些非常重要的列:
oid: 对象标识符 (Object Identifier)。一个在整个数据库中唯一的数字,是这个关系对象的内部主键。relname: 关系名称 (Relation Name)。就是我们平时使用的表名、视图名等,例如'employees'。relnamespace: 关系所属的命名空间 (Relation Namespace)。它存储的是该关系所属的 Schema (模式) 的oid。reltype: 关系类型 (Relation Type)。它存储的是定义此关系行结构的复合类型的oid。relowner: 关系所有者 (Relation Owner)。存储拥有此关系的角色(用户)的oid。relkind: 关系种类 (Relation Kind)。这是一个极其重要的字段,用一个单字符来区分这一行记录到底是什么类型的对象。r= 普通表 (regular relation/table)i= 索引 (index)S= 序列 (Sequence)v= 视图 (view)c= 复合类型 (composite type)f= 外部表 (foreign table)m= 物化视图 (materialized view)
reltuples: 关系元组数 (Relation Tuples)。这是一个估算值,表示表中的行数。查询优化器会用它来制定执行计划。relnatts: 关系属性数 (Relation Number of Attributes)。表示这个关系(主要是表)有多少个列。relhaspkey: 关系有主键 (Relation Has Primary Key)。一个布尔值,表示这个表是否有主键。relacl: 关系访问控制列表 (Relation Access Control List)。就是我们之前讨论过的,存储该对象权限信息的数组。
2. 从名称到磁盘字节的路径是怎样的? (How to go from a name to bytes?)
这是数据库工作的核心路径。我们可以用一个去图书馆找书的比喻来理解这个过程。
你的目标: SELECT * FROM public.employees; (找到 “public部门” 的 “employees” 这本书的所有内容)
- 解析请求 (Parsing)
- 你向图书管理员(PostgreSQL解析器)提出请求。管理员首先确认你的请求符合语法规则。
- 查找目录卡片 (Name Resolution / Catalog Lookup)
- 管理员(系统)会去查询“目录卡片”(系统目录)。
- 首先,它查阅
pg_namespace找到名为public的部门(Schema)的 OID。 - 然后,它查阅
pg_class这本更核心的目录,寻找relname(关系名) 等于employees并且relnamespace(所属schema的OID) 与public的OID相匹配的那一行。
- 定位物理位置 (Find Physical Location)
- 在
pg_class中找到employees表对应的那一行后,管理员就获得了这本书的关键物理信息:reltablespace: 书所在的馆区(表空间),比如“主馆区”或“南区SSD馆”。这决定了文件存储的根目录。relfilenode: 书在馆区里的唯一书架编号。这个编号直接对应磁盘上的一个文件名。
- 至此,PostgreSQL已经知道了要找的数据存储在哪个目录下的哪个文件里。
- 在
- 取回数据页 (Buffer Manager)
- 现在,图书管理员派一个助手(缓冲区管理器 Buffer Manager)去取书。
- 助手会先看看“常用书手推车”(共享内存缓冲区 Shared Buffers)上有没有这本书的某一页。如果有,就直接从内存里拿,非常快。
- 如果内存里没有,助手才会去那个物理书架(磁盘 Disk)上把对应的数据页取出来,并放到手推车上以备后续使用。
- 解读内容 (Tuple Access)
- 助手把数据页(书的一页)拿回来后,图书管理员(访问方法 Heap Access Method)知道这本书的排版格式,它懂得如何从这一页中精确地读出每一行字(元组 Tuple),并检查这行字你是否有权限看(MVCC可见性检查),最后把内容呈现给你。
总结:这个过程是一个从逻辑名称到物理地址的层层解析。数据库通过查询它自身的元数据(系统目录),将一个我们能理解的表名(如 employees),一步步翻译成磁盘上某个文件的某个偏移量,最终将字节流读取到内存并解析成我们需要的行数据。
总结
Pg的核心设计哲学是一切皆为表。不仅用户数据存储在表中,所有关于数据库自身的元数据(关于表、数据库、函数、权限等所有信息)都在特殊的系统表中。