PostgreSQL表名超长踩坑记

2 阅读3分钟

你以为的PostgreSQL支持的表名最长长度是多少?256个字符?512个字符?

这里先卖个关子。

大家是否还记得之前流传的Linux中 rm -rf ${LOG_DIR}/命令的一个梗,由于未传参LOG_DIR变成了空值,于是执行的命令就变成了rm -rf /,然后服务器根目录就被删除了个干干净净。

我也犯了类似的错误,我要把一个过期的日志表给删除,由于表名超长了,并且被截断执行了,导致不该删除的表也被删除了。

模拟重现步骤如下:

第一步

创建模拟的正式表

-- 正式表建表语句
create table t_loooooooooooooooooooooooooooooooooooooooooong_name (name varchar(10));

第二步

将正式表重命名为备份表。

alter table t_loooooooooooooooooooooooooooooooooooooooooong_name rename to t_loooooooooooooooooooooooooooooooooooooooooong_name_bak_20260303;

执行时,你会发现,居然成功执行了。可是,再仔细一看,怎么还有提示:

identifier "t_loooooooooooooooooooooooooooooooooooooooooong_name_bak_20260303" will be truncated to "t_loooooooooooooooooooooooooooooooooooooooooong_name_bak_202603"

第三步

根据备份表,重建一张正式表。你猜,这一步会成功执行吗?

答案是会的,并且会出现和第二步一样的提示。

create table t_loooooooooooooooooooooooooooooooooooooooooong_name (like t_loooooooooooooooooooooooooooooooooooooooooong_name_bak_20260303 including all);

第四步,重要的一步来了

假设我要滚动删除20260302那天的备份表,这里有一个隐含逻辑是20260302暂时还不存在,因为这是个新逻辑。

执行下面的SQL命令:

drop table t_loooooooooooooooooooooooooooooooooooooooooong_name_bak_20260302;

结果你应该能想到,又被截断执行了。并且把表t_loooooooooooooooooooooooooooooooooooooooooong_name_bak_202603删除了。也就是说,这个表刚刚备份出来就被删除了。

结论

来看一下,截断后的表名有多长。测试SQL如下:

select length('t_loooooooooooooooooooooooooooooooooooooooooong_name_bak_202603');

length|
------+
    63|

想不到吧,只有63个字符。

总结

关于这个特性,官方文档Identifiers and Key Words一节是有说明的,原文如下:

The system uses no more than NAMEDATALEN-1 bytes of an identifier; longer names can be written in commands, but they will be truncated. By default, NAMEDATALEN is 64 so the maximum identifier length is 63 bytes. If this limit is problematic, it can be raised by changing the NAMEDATALEN constant in src/include/pg_config_manual.h.

大意是标识符字节数不超过 NAMEDATALEN-1,具体是多少?就是 64-1=63

需要注意的是,原文中提及了对于多字节字符,比如中文名称,肯定达不到63,因为是按字节数算的。

我可以修改配置吗?增大范围。

不好意思,改不了,这个是编译期常量。如果你要自己编译一个版本是可以的。上面的原文引用已经列出的源码的修改位置了。

注意:官方说的是标识符,没说表名。也就是说类似,字段名、视图名等等都是适用的。

参考

PostgreSQL: Documentation: 18: 4.1. Lexical Structure