PostgreSQL 用 pg_quota 插件可实现数据库级磁盘配额,但需预加载、以字节为单位设置且仅限数据文件;MySQL 不支持库级存储配额;SQLite 用 max_page_count 限制大小但受 page_size 影响;PVC 配额非运行时强制,不可替代数据库内配额。
PostgreSQL 中用 pg_quota 插件限制单个数据库的磁盘使用量
postgresql 本身不支持数据库级存储配额,必须靠插件实现;pg_quota 是目前最稳定、适配 pg 14–16 的方案,但它只在数据库启动时读取配额配置,运行中修改需 reload 或重启。
常见错误现象:ERROR: quota exceeded for database "mydb" 出现前毫无征兆,因为插件默认不主动检查,得靠触发写入(如 INSERT、CREATE TABLE)才校验。
- 安装后必须在
postgresql.conf中显式启用:shared_preload_libraries = 'pg_quota',漏掉这行插件根本不会加载 - 配额单位是字节,不是 MB/GB —— 设
1073741824才是 1GB,写成1G或1024M会静默失败 - 只限制数据文件(
base/下),不包含 WAL、日志、临时文件;WAL 暴涨仍可能撑爆磁盘
MySQL 8.0+ 用 CREATE USER ... WITH MAX_QUERIES_PER_HOUR 不起作用?别搞混了
MySQL 的资源限制全是针对用户(USER),不是数据库(SCHEMA)。想限制某个库的存储空间,它压根没这个功能 —— MAX_QUERIES_PER_HOUR、MAX_UPDATES_PER_HOUR 管的是操作频次,和磁盘无关。
真正能碰存储的只有 INFORMATION_SCHEMA.INNODB_TABLESPACES 和 sys.schema_table_statistics 这类只读视图,没法设阈值或自动拦截。
- 如果硬要“模拟”配额,只能靠外部脚本定期查
data_length + index_length(从information_schema.tables),超限时DROP USER或REVOKE INSERT ON mydb.* - Percona Server 有
max_disk_usage变量,但仅限于archive引擎表,通用性差 - MySQL 8.4 开始实验性支持
RESOURCE GROUPS,但依然不涉及磁盘配额
SQLite 中用 PRAGMA max_page_count 控制数据库大小的实际效果
PRAGMA max_page_count 是 SQLite 少数能直接限制总大小的机制,但它管的是页数,不是字节数;最终大小取决于 page_size,而后者在数据库首次创建后就固定了。
容易踩的坑:执行 PRAGMA max_page_count = 10000 后,如果 page_size 是默认的 4096 字节,理论上限就是 ~39MB;但一旦 VACUUM 或写入大量 blob,实际占用可能远低于此 —— 因为页内填充率不固定。
- 该 PRAGMA 必须在数据库打开后、任何写操作前设置,否则返回 0 且无提示
- 它不阻止
ATTACH其他数据库,附加库的大小完全不受限 - 出错时抛
database or disk is full,但应用层很难区分是磁盘满还是配额满
为什么 Kubernetes PersistentVolumeClaim 配额不能替代数据库内配额
PVC 的 resources.requests.storage 是给调度器看的,不是运行时强制限制。底层存储驱动(比如 NFS、Ceph RBD、hostPath)是否真做配额,全看它自己 —— 大部分 hostPath 和 NFS 不校验,PVC 配额形同虚设。
典型反例:一个 PVC 申明了 10Gi,挂载到 PostgreSQL 的 PGDATA,但 PostgreSQL 仍在里面写到 15Gi 才报错,因为 OS 层没拦住。
- 只有 Ceph RBD +
quota特性开启、或某些企业版 NAS 才真能拦截写入 - 即使底层支持,也只限制整个卷,无法细分到单个数据库或 schema
- 数据库崩溃后残留的 wal、pg_xact、pg_logical 目录可能绕过配额统计,导致误判
真正要稳,得数据库内配额 + 外部监控双保险;光靠某一层,迟早遇到配额失效却没告警的情况。










