引言

在使用不同的关系型数据库时,你很快会发现一个令人困惑的现象:SQLite 里似乎没有"模式"的概念,MySQL 把模式和数据库画了等号,PostgreSQL 则冒出了一个 public 模式,Oracle 又把模式和用户绑在一起……同样是关系型数据库,为什么差异这么大?

本文将从 SQL 标准出发,逐一梳理主流数据库对模式的实现方式,并重点对比它们在跨模式查询上的行为差异,帮助你建立清晰的全局认知。


一、SQL 标准中的命名层级

SQL 标准定义了一个三层命名体系:

Catalog  →  Schema  →  Table (Object)

一张表的完全限定名应该写作 catalog.schema.table。其中:

  • Catalog 通常对应一个数据库实例或数据库。
  • Schema 是一个逻辑命名空间,用来对表、视图、函数等数据库对象进行分组。
  • Table 是最终的数据库对象。

然而,各家数据库对这套标准的采纳程度参差不齐,这正是混乱的根源。


二、各数据库的模式实现方式

2.1 PostgreSQL — 最接近 SQL 标准

PostgreSQL 的层级结构为:

Server  →  Database  →  Schema  →  Table
  • 每个数据库创建时自带一个 public 模式,作为默认的命名空间。
  • 日常写 SELECT * FROM users 等价于 SELECT * FROM public.users
  • 可以自由创建多个模式,用于业务模块隔离或多租户架构。
  • 通过 search_path 参数控制模式的默认查找顺序。
-- 创建新模式
CREATE SCHEMA sales;
CREATE SCHEMA inventory;

-- 在指定模式下建表
CREATE TABLE sales.orders (id SERIAL PRIMARY KEY, amount NUMERIC);
CREATE TABLE inventory.products (id SERIAL PRIMARY KEY, name TEXT);

-- 修改默认搜索路径
SET search_path TO sales, public;

2.2 MySQL — 模式与数据库合二为一

MySQL 将 Schema 和 Database 视为完全等价的同义词

Server  →  Database (= Schema)  →  Table
  • CREATE DATABASECREATE SCHEMA 是完全相同的操作。
  • 不存在 Database 下面再细分 Schema 这一层。
  • 通过 USE mydb 切换的"数据库",在概念上就充当了 Schema 的角色。
-- 以下两条语句完全等价
CREATE DATABASE myapp;
CREATE SCHEMA myapp;

-- 切换当前数据库(即模式)
USE myapp;

2.3 SQL Server — 完整的层级支持

SQL Server 的层级结构为:

Server  →  Database  →  Schema  →  Table
  • 每个数据库有一个默认模式 dbo(database owner),类似于 PostgreSQL 的 public
  • 模式可以与权限管理结合,按模式粒度进行授权控制。
-- 创建模式并授权
CREATE SCHEMA hr AUTHORIZATION hr_admin;

-- 在模式下建表
CREATE TABLE hr.employees (id INT PRIMARY KEY, name NVARCHAR(100));

2.4 Oracle — 用户即模式

Oracle 的做法非常独特:

Server (Instance)  →  User (= Schema)  →  Table
  • 每个用户自动拥有一个同名的模式,两者一一绑定
  • 访问其他用户的表时,前缀就是用户名。
  • 可以通过 synonym(同义词)简化跨模式访问。
-- 访问其他用户的表
SELECT * FROM alice.orders;

-- 创建同义词以省略前缀
CREATE SYNONYM orders FOR alice.orders;

2.5 SQLite — 几乎没有模式概念

SQLite 作为嵌入式数据库,一个文件就是一个数据库,所有表"平铺"存放:

文件 (Database)  →  Table
  • 没有独立的 Schema 层。
  • 通过 ATTACH DATABASE 可以将多个数据库文件挂载到同一连接中,用 dbname.table 的方式访问。
-- 挂载另一个数据库文件
ATTACH DATABASE 'analytics.db' AS analytics;

-- 默认数据库的别名为 main
SELECT * FROM main.users;
SELECT * FROM analytics.events;

2.6 各数据库模式实现对比一览

数据库层级结构默认模式模式与其他概念的关系
PostgreSQLDatabase → Schema → Tablepublic独立的命名空间
MySQLDatabase(=Schema) → Table无独立模式Schema 等价于 Database
SQL ServerDatabase → Schema → Tabledbo独立的命名空间,可绑定权限
OracleInstance → User(=Schema)→Table用户同名Schema 与 User 一一绑定
SQLiteFile(Database) → Table无模式概念

三、跨模式查询的行为差异

理解了各数据库对模式的定义后,更重要的是了解它们在跨模式(跨命名空间)查询上的表现。

3.1 同模式查询

所有数据库的行为一致——直接使用表名,无需任何前缀:

SELECT * FROM users JOIN orders ON users.id = orders.user_id;

3.2 跨模式查询

PostgreSQL:跨 Schema 无缝,跨 Database 不可直接访问

-- 跨 Schema(同一 Database 内)—— 无缝支持
SELECT a.*, b.*
FROM sales.orders a
JOIN inventory.products b ON a.product_id = b.id;

-- 跨 Database —— 不支持直接查询,需借助扩展
-- 方式一:dblink
SELECT * FROM dblink('dbname=other_db', 'SELECT id, name FROM users') 
  AS t(id INT, name TEXT);

-- 方式二:postgres_fdw(外部数据包装器)
CREATE EXTENSION postgres_fdw;
CREATE SERVER remote FOREIGN DATA WRAPPER postgres_fdw OPTIONS (dbname 'other_db');
CREATE FOREIGN TABLE remote_users (...) SERVER remote OPTIONS (table_name 'users');

PostgreSQL 的设计哲学是:Schema 做逻辑隔离(可跨),Database 做物理隔离(不可直接跨)

MySQL:跨"数据库"即跨"模式",原生支持

-- 跨 Database(即跨 Schema)—— 直接支持
SELECT a.*, b.*
FROM app_db.orders a
JOIN analytics_db.events b ON a.user_id = b.user_id;

只要连接用户对目标数据库有权限,就能直接跨库 JOIN,无需任何额外配置。

SQL Server:跨 Schema 和跨 Database 均原生支持

-- 跨 Schema(同一 Database 内)
SELECT * FROM sales.orders JOIN hr.employees ON ...;

-- 跨 Database(同一 Server 内)—— 三段式命名
SELECT * FROM db1.sales.orders JOIN db2.hr.employees ON ...;

-- 跨 Server —— 四段式命名,需配置 Linked Server
SELECT * FROM remote_server.db1.sales.orders;

SQL Server 在这方面是最灵活的,支持最完整的层级穿透。

Oracle:跨 Schema 即跨用户,跨实例需 DB Link

-- 跨 Schema(跨用户)—— 需授权
GRANT SELECT ON orders TO bob;
SELECT * FROM alice.orders JOIN bob.products ON ...;

-- 使用同义词简化
CREATE SYNONYM orders FOR alice.orders;
SELECT * FROM orders;  -- 无需再写前缀

-- 跨实例 —— 通过 DB Link
CREATE DATABASE LINK remote_link CONNECT TO user IDENTIFIED BY pass USING 'remote_db';
SELECT * FROM orders@remote_link;

SQLite:通过 ATTACH 模拟跨库查询

ATTACH DATABASE 'shop.db' AS shop;
ATTACH DATABASE 'log.db' AS log;

-- 跨库 JOIN
SELECT a.*, b.*
FROM shop.products a
JOIN log.access_log b ON a.id = b.product_id;

3.3 跨模式查询能力对比一览

数据库同模式查询跨模式查询跨数据库查询
PostgreSQL直接查询schema.table,无缝不支持直接跨,需 dblink/fdw
MySQL直接查询即跨 Database:db.table同左,原生支持
SQL Server直接查询schema.table,无缝db.schema.table,原生支持
Oracle直接查询user.table,需授权需 DB Link
SQLite直接查询无模式概念ATTACH 后用 dbname.table

四、设计取舍与选型建议

不同数据库的模式处理方式,背后反映的是不同的设计哲学:

PostgreSQL 提供了最严谨的隔离模型。Schema 间可以自由穿透,但 Database 之间是硬隔离。这种设计适合需要严格数据隔离的场景,例如多租户 SaaS 应用(每个租户一个 Schema 或一个 Database)。

MySQL 牺牲了一层命名空间的灵活性,换来了极低的跨库查询门槛。对于中小型项目、快速原型开发、或者不需要复杂命名空间管理的场景,这种简洁性反而是优势。

SQL Server 在层级完整性和跨层查询能力上做到了最佳平衡,适合大型企业级应用,尤其是需要在同一实例中管理多个业务系统的场景。

Oracle 将模式与用户绑定的设计,使得权限管理非常直观——谁的模式谁负责。在对安全性要求极高的金融、政务等领域有其独特优势。

SQLite 作为嵌入式数据库,轻量简洁是第一优先级,不引入模式概念是合理的选择。


五、结语

"模式"看似是一个简单的概念,但各数据库的实现差异会直接影响你的数据库设计、权限管理和跨模块查询方式。在做技术选型或跨数据库迁移时,理解这些差异可以帮你避免很多意想不到的坑。核心原则是:先弄清楚你所使用的数据库把 Schema 映射到了哪一层,再据此设计你的命名空间和隔离策略

标签: none

添加新评论