千家信息网

PostgreSQL DBA(113) - pgAdmin(Don't do this:Don't use char(n))

发表于:2025-11-07 作者:千家信息网编辑
千家信息网最后更新 2025年11月07日,no zuo no die系列,来自于pg的wiki。这一节的内容是:不要使用char(n) 。理由是:Any string you insert into a char(n) field will
千家信息网最后更新 2025年11月07日PostgreSQL DBA(113) - pgAdmin(Don't do this:Don't use char(n))

no zuo no die系列,来自于pg的wiki。
这一节的内容是:不要使用char(n) 。
理由是:

Any string you insert into a char(n) field will be padded with spaces to the declared width. That's probably not what you actually want.
The manual says:
Values of type character are physically padded with spaces to the specified width n, and are stored and displayed that way. However, trailing spaces are treated as semantically insignificant and disregarded when comparing two values of type character. In collations where whitespace is significant, this behavior can produce unexpected results; for example SELECT 'a '::CHAR(2) collate "C" < E'a\n'::CHAR(2) returns true, even though C locale would consider a space to be greater than a newline. Trailing spaces are removed when converting a character value to one of the other string types. Note that trailing spaces are semantically significant in character varying and text values, and when using pattern matching, that is LIKE and regular expressions.
That should scare you off it.
The space-padding does waste space, but doesn't make operations on it any faster; in fact the reverse, thanks to the need to strip spaces in many contexts.
It's important to note that from a storage point of view char(n) is not a fixed-width type. The actual number of bytes varies since characters may take more than one byte, and the stored values are therefore treated as variable-length anyway (even though the space padding is included in the storage).

原因是期望指定n长,但由于字符编码(如中文字符,GB2312是2个字节,而UTF8是3个字节)的原因,实际跟预想的不符,而且会出现影响排序等其他副作用。

testdb=# drop table if exists t_char;DROP TABLEtestdb=# create table t_char(id int,c1 char(10),c2 varchar(10));CREATE TABLEtestdb=# testdb=# insert into t_char values(1,'测试123','123123');INSERT 0 1testdb=# insert into t_char values(2,'abc123','123123');INSERT 0 1testdb=# testdb=# insert into t_char values(3,'a','a ');INSERT 0 1testdb=# insert into t_char values(4,E'a\n',E'a\n');INSERT 0 1testdb=#

使用length函数获取长度

testdb=# select id,length(c1),length(c2) from t_char order by id; id | length | length ----+--------+--------  1 |      5 |      6  2 |      6 |      6  3 |      1 |      2  4 |      2 |      2(4 rows)

如上所述,使用length函数获取的实际是字符个数而不是实际的字节数,如"测试123"实际的字节数是9+5=14字节。

testdb=# select id,length(c1),octet_length(c1),length(c2),octet_length(c2) from t_char order by id; id | length | octet_length | length | octet_length ----+--------+--------------+--------+--------------  1 |      5 |           14 |      6 |            6  2 |      6 |           10 |      6 |            6  3 |      1 |           10 |      2 |            2  4 |      2 |           10 |      2 |            2(4 rows)

在字符串比较上面,虽然空格的ascii码值(0x20)比'\n'(0x0a)要大,但查询的实际效果看起来却是char(10)定义的'a'比'a\n'要小:

testdb=# select E'a\n'::bytea; bytea  -------- \x610a(1 row)testdb=# select E'a '::bytea; bytea  -------- \x6120(1 row)testdb=# select * from t_char where c1 < E'a\n'; id |     c1     | c2 ----+------------+----  3 | a          | a (1 row)

参考资料
Don't Do This

字节 实际 字符 函数 原因 测试 个数 内容 副作用 参考资料 如上 如上所述 字符串 效果 理由 空格 编码 资料 长度 中文 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技企业 转型 互联网 潍坊联想服务器代理零售 国产单串口服务器价格 咸宁管理软件开发供应 网站服务器的日志可以删吗 高级数据库开发培训 sql 链接服务器连不上 手机下载资源服务器异常怎么办 上海数据网络技术分类技术 我的世界服务器远古赞歌 计算机三级网络技术好过么 建行软件开发工资待遇 数据库字段怎么看重复 无法识别服务器的原因 mimic数据库 论文 access数据库和程序 从事软件开发的经营范围 学习国家网络安全知识心得 达梦数据库客户端怎么使用 关系型数据库的数据逻辑结构是 psql删除数据库语句 电子科技大学软件学院网络安全 魔域服务器怎么查看人物 杭州网络安全线上培训 手机下载资源服务器异常怎么办 如何获得网络安全知识 涉密计算机网络安全保密措施 数据库密码无法更改密码 网络安全中心人员配置 海致网络技术有限公司靠谱吗
0