在PostgreSQL中执行CREATE DATABASE时,数据库并不是凭空创建的,而是复制一个已经存在的数据库作为起点,这个被复制的数据库就是模板数据库。掌握模板数据库的原理,不仅能解释一些奇怪的建库行为,还能用它实现数据库克隆、批量初始化等实用功能。

模板数据库的工作原理与两个内置模板
PostgreSQL默认提供两个模板数据库:template0和template1。CREATE DATABASE语句如果不指定TEMPLATE参数,默认会复制template1。这意味着新建的数据库会继承template1中的所有对象,包括表、函数、扩展、编码设置等。很多人发现自己的新建库里凭空多出一些表或者默认权限配置,根源就在这里。
template1和template0的区别在于:template1可以被修改、可以连接进去执行任意操作,适合用来定制企业标准模板;而template0是一个纯净的、不可修改的初始模板,只保证数据库集群初始安装时的状态。当template1被污染(比如不小心写入了垃圾对象、字符集配置混乱)时,可以指定TEMPLATE template0来创建一个干净的数据库,甚至可以在建库时指定新的编码和区域设置:
-- 从 template0 克隆,并指定不同的编码和区域 CREATE DATABASE mydb TEMPLATE template0 ENCODING 'UTF8' LC_COLLATE 'en_US.UTF-8' LC_CTYPE 'en_US.UTF-8';
注意,从template1克隆时不允许修改编码和LC设置,因为克隆要求编码与模板一致。只有template0可以跨编码建库,这是两个模板最关键的实用差异。另外,template0默认不允许连接,如果确有必要修改它,需要先用ALTER DATABASE template0 ALLOW_CONNECTIONS true打开连接,改完再关掉。
用TEMPLATE参数实现任意数据库的克隆
CREATE DATABASE的TEMPLATE参数并不限于模板库,任何数据库都可以作为模板。这就是PostgreSQL原生的数据库克隆方式,常用于搭建测试环境、做数据快照、批量复制业务库。例如想把生产库business克隆一份给开发调试:
-- 把 business 库当作模板,克隆出一份新库 CREATE DATABASE business_dev TEMPLATE business; -- 克隆时指定新的属主和表空间 CREATE DATABASE business_test TEMPLATE business OWNER devuser TABLESPACE fast_ssd;
克隆过程在底层走的是文件级别的复制,速度通常远快于逻辑导出再导入,尤其适合超大库的快速复制。克隆出来的数据库包含模板库的全部表结构和数据,但不包含模板库中的复制槽、临时表以及针对旧库本身的权限映射细节,这点在迁移场景要留意。
使用TEMPLATE克隆有一个硬性限制:源数据库在克隆期间不能有其他连接。如果源库正在被业务使用,CREATE DATABASE会直接报错source database is being accessed by other users。处理办法有两种:一是先执行ALTER DATABASE business ALLOW_CONNECTIONS false禁止新连接,再配合pg_terminate_backend踢掉存量连接,克隆完成后恢复;二是选择业务低峰期,用pg_dump导出代替克隆。实践中更优雅的做法是写一个事务块,先断连、克隆、再放开:
BEGIN; -- 禁止新连接 ALTER DATABASE business ALLOW_CONNECTIONS false; -- 终止已有连接 SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'business' AND pid <> pg_backend_pid(); -- 执行克隆 CREATE DATABASE business_snapshot TEMPLATE business; -- 恢复连接 ALTER DATABASE business ALLOW_CONNECTIONS true; COMMIT;
定制template1与常见误区
如果团队每个新库都需要统一的扩展、公共函数或默认权限,最省事的做法是直接把这些对象放进template1。此后所有CREATE DATABASE都会自动带上这些内容,相当于给整个集群定义了默认初始化脚本:
-- 连接到 template1 并添加公共对象 \c template1 CREATE EXTENSION IF NOT EXISTS pgcrypto; CREATE EXTENSION IF NOT EXISTS "uuid-ossp"; -- 建一个公共 schema 供所有新库使用 CREATE SCHEMA IF NOT EXISTS common; COMMENT ON SCHEMA common IS '团队公共对象';
修改template1有几个常见误区需要避开。第一,往template1里塞的东西会进入所有新库,包括测试库和临时库,如果把大表或测试数据放进去,会持续浪费磁盘并拖慢建库速度,模板里应该只保留轻量的定义性对象。第二,模板库本身可以再套模板,template1也带有datistemplate标记,在pg_database里可以通过查询SELECT datname, datistemplate FROM pg_database确认哪些库是模板库,具备克隆资格。
第三,有人会把业务库直接标记为模板库,即执行ALTER DATABASE business IS_TEMPLATE true。这样做的好处是简化克隆语句、防止误删,因为模板库不允许直接DROP DATABASE。但要清楚标记为模板的库会限制并发连接场景下的克隆操作,评估业务模式后再决定。如果只是临时克隆一次,不需要打模板标记,TEMPLATE参数本身就够用了。
总结来看,模板数据库是PostgreSQL建库机制的核心:日常用template1承载团队规范,用template0兜底保证纯净克隆,用TEMPLATE参数灵活复制任意库。理解这三种用法,建库效率和环境一致性都会明显提升。
PostgreSQL模板数据库CREATE DATABASE修改时间:2026-09-10 21:12:39