ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

PostgreSQL 标识符 63 字节上限:截断机制、_fkey 后缀保护与 NAMEDATALEN 源码解析

PostgreSQL 标识符 63 字节上限:截断机制、_fkey 后缀保护与 NAMEDATALEN 源码解析 文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载PostgreSQL 对表名、列名、约束名等所有标识符施加了 63 字节的硬性长度上限超长标识符并不会报错而是被自动截断这一行为在日常建表、加约束时极易被忽视并引发隐患。本文将结合本仓库的 PostgreSQL 系列笔记完整解析 63 字节限制的来龙去脉、截断时的 NOTICE 提示、自动生成标识符的“保后缀”策略以及该上限的源码出处NAMEDATALEN - 1。63 字节PostgreSQL 标识符的硬性上限在 PostgreSQL 中所有标识符——表名table names、列名column names、约束名constraint names等——的长度都被限制为最多 63 字节。这个限制并不是“超过就报错”而是更隐蔽可以写入超过 63 字符的标识符但 PostgreSQL 会将其截断到允许的 63 字节长度并给出一条 NOTICE 提示。这与本仓库中另一则笔记 表名默认被当作小写处理 所揭示的行为类似PostgreSQL 会在处理标识符时对名称进行规范化折叠大小写、截断超长部分因此开发者实际写下的名字与数据库最终存储的名字可能并不一致。理解这套标识符处理规则是避免“名字对不上”“约束找不到”等困惑的前提。超长标识符不会报错而是被截断直接看效果最直观。在 psql 中执行下面这条alter table尝试添加一个明显超过 63 字节的 CHECK 约束名 alter table articles add constraint this_constraint_is_going_to_be_longer_than_sixty_three_characters_id_idx check (char_length(title) 0); NOTICE: identifier this_constraint_is_going_to_be_longer_than_sixty_three_characters_id_idx will be truncated to this_constraint_is_going_to_be_longer_than_sixty_three_characte ALTER TABLE两个关键信息值得注意操作本身成功命令返回ALTER TABLE约束照常创建全程没有报错只有一条NOTICE。NOTICE 明确告知截断结果PostgreSQL 会明确指出超长标识符将被截断为哪个名字。上例中原本 78 字节的约束名被截断为 63 字节的this_constraint_is_going_to_be_longer_than_sixty_three_characte——注意末尾少了s_id_idx几个字符。这种“静默截断 NOTICE 提醒”的设计意味着只要没盯着服务端日志或 psql 输出你可能永远不会发现约束名、索引名已经被悄悄改写了。截断后的名字才是真实存在的名字截断一旦发生之后所有针对该对象的操作都必须使用截断后的名字。例如删除约束时必须写alter table articles drop constraint this_constraint_is_going_to_be_longer_than_sixty_three_characte;如果按自己书写的全名去drop constraint会得到 “constraint does not exist” 之类的错误——因为数据库里存的是截断后的版本。想确认表上约束的真实存储名字可以查询系统目录pg_constraint并用pg_get_constraintdef(oid)重建约束定义。仓库笔记 Show Reconstructed Constraints For A Table 给出了完整的示例 select conname, pg_get_constraintdef(oid) from pg_constraint where conrelid reading_statuses::regclass; conname | pg_get_constraintdef ----------------------------------------------------------------------------------------------------- reading_statuses_pkey | PRIMARY KEY (id) fk_rails_17ee7cb2c4 | FOREIGN KEY (user_id) REFERENCES users(id) fk_rails_0d3729339f | FOREIGN KEY (book_id) REFERENCES books(id) reading_statuses_valid_status_check | CHECK (...) (4 rows)通过conname看到的名字就是经过 PostgreSQL 规范化含截断后的最终名字也是你在所有后续 SQL 中真正需要引用的名字。自动生成的标识符从中间截断保住_fkey等后缀超长标识符不仅会发生在开发者手写的名字上PostgreSQL 自动生成的标识符同样受 63 字节限制。最常见的场景是外键约束当你在alter table中省略约束名时PostgreSQL 会按约定自动生成xxx_fkey这类名字。仓库笔记 Add Foreign Key Constraint Without A Full Lock 展示了这种命名约定alter table books add constraint fk_books_authors foreign key (author_id) references authors(id) not valid;这里手写了fk_books_authors但如果省略constraint子句PostgreSQL 生成的默认名通常是表名_列名_fkey而在 Rails 等框架下则常见fk_rails_hash这样的短名如上面的fk_rails_17ee7cb2c4。问题在于当表名、列名本身较长时自动拼出的_fkey全名可能轻松超过 63 字节。此时 PostgreSQL 的截断策略与手写标识符不同——它会在中间某个位置截断而不是从尾部硬切目的是保住约定俗成的后缀例如以_fkey结尾。这样生成的名字依然符合“一眼看出是外键约束”的命名惯例。这也解释了为什么在真实生产库中你会看到诸如books_authors_very_long_column_name_fk截断版这样的名字——命名习惯被保留了但可读性已经大打折扣。63 字节的由来NAMEDATALEN - 163 这个数字并非拍脑袋定下的它直接来自 PostgreSQL 源码中的一个编译期常量NAMEDATALEN - 1默认情况下NAMEDATALEN的值为64因此标识符上限为 63。这个值是编译期硬编码的而不是运行时配置项无法通过postgresql.conf之类的配置文件调整。如果确实需要可以在 PostgreSQL 源码中修改NAMEDATALEN位于源码的pg_config_manual.h中后重新编译数据库。之所以预留 1 字节的余量是为了容纳字符串的结尾空字符\0即内部缓冲区大小为NAMEDATALEN64 字节其中最多 63 字节用于标识符本身。正如原文所说“Yay, open-source database implementations”——开源数据库的好处在于这种底层限制的出处是透明的需要时甚至可以亲自改掉它。不过在实际生产环境中修改后需要重新编译并可能导致与生态工具迁移工具、ORM 生成的名称的不兼容绝大多数团队不应走到这一步。注意上限单位是字节不是字符限制单位是63 字节而非“63 个字符”。对于纯 ASCII 标识符1 字节 1 字符63 字符即上限但一旦使用多字节字符如中文、日文、emoji 命名的标识符每个字符可能占用 24 字节实际可用的字符数会显著少于 63。截断也是按字节进行的因此含多字节字符的超长标识符被截断后其边界不一定落在完整的字符边界上。实用建议无论是 ASCII 还是多字节命名都留足余量远离 63 字节这条红线。工程实践如何避开 63 字节陷阱结合本仓库 PostgreSQL 相关笔记的实践可以从以下几个层面规避截断带来的麻烦命名从源头保持精简约束名、索引名、外键名都采用“表名 关键列 类型后缀”的短命名例如fk_books_authors、uq_users_email把长度控制在 63 字节以内让截断根本不发生。沿用 snake_case 小写命名仓库笔记 Table Names Are Treated As Lower-Case By Default 强调PostgreSQL 默认把未加引号的标识符折叠为小写。保持全小写 snake_case 既能规避大小写混淆也让名字更短、更符合约定。了解框架的自动命名Rails 等框架默认生成fk_rails_16 位 hash这类固定长度短名见上文pg_constraint查询结果天然不会超长手写长表名与长列名组合时才最容易踩中自动拼接超长的坑。改名前留意连带命名仓库笔记 Renaming A Table 提醒alter table ... rename to ...会更新外键引用但与旧表同名的序列、约束等名字不再遵循原约定——这些名字若因重命名变得更长同样可能触及 63 字节截断需一并检查。用系统目录自查建完约束后通过pg_constraint.conname与pg_get_constraintdef()核对实际存储的约束名方法见 Show Reconstructed Constraints For A Table确保迁移脚本后续引用的名字与库中真实名字一致。小结PostgreSQL 的标识符上限是 63 字节来源于编译期常量NAMEDATALEN - 1默认NAMEDATALEN 64。超长标识符不会被拒绝而是被截断并给出 NOTICE自动生成的标识符如外键的_fkey名则会从中间截断以保住后缀约定。理解这一机制能帮你解释许多“名字对不上”的怪象并在设计表结构、编写迁移脚本时提前规避。更多 PostgreSQL 命名与约束相关的实践可继续翻阅本仓库的 PostgreSQL 笔记目录。赞分享文档教程知识库【免费下载链接】til:memo: Today I Learned项目地址https://gitcode.com/gh_mirrors/ti/til点击查看免费下载相关推荐PostgreSQL技术解析标识符最大长度限制为63字节PostgreSQL技术解析标识符最大长度限制为63字节 标识符长度限制概述 在PostgreSQL数据库中各种标识符包括表名、列名、约束名等都有一个明文档教程知识库curl --max-filesize 使用详解文件大小上限限制机制、字节后缀语法与退出码 63curl max filesize 使用详解文件大小上限限制机制、字节后缀语法与退出码 63 max filesize 是 curl 命令行工具中用于限制下载CLI网络通信零运行时原子 CSS 框架vanilla-extract Sprinkles 完整实战指南零运行时原子 CSS 框架vanilla extract Sprinkles 完整实战指南 vanilla extract 生态中 Sprinkles ht前端开发工具上一篇用 Firehose 构建实时 Web 数据流监控Marketing Skills 仓库中的 SSE 竞争情报集成指南下一篇open-design 仓库中的 IBM Carbon 设计系统还原指南从 --cds-* Token 体系到 Agent 提示词工程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表