暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL | Oracle、PostgreSQL中char、varchar的差异,能省一点空间

Oracle、PostgreSQL中char、varchar的区别。

在 Oracle中,char和 varchar2表示字节的数量,而 PostgreSQL会转换成character和character varying,表示字符的数量。对于UTF-8字符集来说,往往一个中文代表一个字符,而一个中文占用3个字节。因此在Oracle中用char (10)只能保存3个汉字,即3个字符,而使用PostgreSQL可以保存10个字符。

下面的图展示了使用AWS Schema Conversion Tool转换的表结构:

PostgreSQL中character和character varying

在PostgreSQL的t1表中插入测试数据,使用length函数查看字符串中的字符数,同时使用OCTET_LENGTH查询字符串中的字节数。

postgres=# \d test.t1
                         Table "test.t1"
 Column |         Type          | Collation | Nullable | Default 
--------+-----------------------+-----------+----------+---------
 name1  | character(10)         |           |          | 
 name2  | character varying(10) |           |          | 

postgres=# select * from test.t1;
        name1         |        name2         
----------------------+----------------------
 我                   | 我
 我是                 | 我是
 我是一               | 我是一
 我是一个             | 我是一个
 我是一个小           | 我是一个小
 我是一个小萝         | 我是一个小萝
 我是一个小萝莉       | 我是一个小萝莉
 我是一个小萝莉是     | 我是一个小萝莉是
 我是一个小萝莉是不   | 我是一个小萝莉是不
 我是一个小萝莉是不是 | 我是一个小萝莉是不是
(10 rows)

postgres=# SELECT LENGTH(name1),LENGTH(name2) from test.t1;
 length | length 
--------+--------
      1 |      1
      2 |      2
      3 |      3
      4 |      4
      5 |      5
      6 |      6
      7 |      7
      8 |      8
      9 |      9
     10 |     10
(10 rows)

postgres=# SELECT OCTET_LENGTH(name1),OCTET_LENGTH(name2) from test.t1;
 octet_length | octet_length 
--------------+--------------
           12 |            3
           14 |            6
           16 |            9
           18 |           12
           20 |           15
           22 |           18
           24 |           21
           26 |           24
           28 |           27
           30 |           30
(10 rows)

显然,在这里可以插入10个汉字,UTF-8默认的一个汉字是3字节,因此在这里插入10个汉字就是30字节。

让我们用orafce的varchar2来试试兼容型。

postgres=# \d test.t2
                    Table "test.t2"
 Column |     Type     | Collation | Nullable | Default 
--------+--------------+-----------+----------+---------
 name1  | varchar2(10) |           |          | 

postgres=# insert into test.t2 values('我是一');
INSERT 0 1
postgres=# insert into test.t2 values('我是一个');
2021-02-08 03:19:27.764 UTC [2561] ERROR:  input value length is 12; too long for type varchar2(10)
2021-02-08 03:19:27.764 UTC [2561] STATEMENT:  insert into test.t2 values('我是一个');
ERROR:  input value length is 12; too long for type varchar2(10)

这次和 Oracle一样,在输入第四个汉字时,直接显示出长度不足。

因此,默认使用 AW Schema Conversion Tool或ora2pg工具进行表结构转换,不会有长度方面的问题,只有一个问题,那就char会产生性能影响。把列的宽度设置的小一点,能让底层page里面更好的填充数据,占用的空间更小。

如下面这个案例所示:

postgres=# create table t3 (a INT,b character(10));
CREATE TABLE
postgres=# INSERT INTO t3 SELECT i/10000,'你好吗' FROM generate_series (1,100000) s(i);
INSERT 0 100000
postgres=# create table t4 (a INT,b character(3));
CREATE TABLE
postgres=# INSERT INTO t4 SELECT i/10000,'你好吗' FROM generate_series (1,100000) s(i);
INSERT 0 100000
postgres=# select pg_size_pretty(pg_relation_size('t3'));
pg_size_pretty
----------------
5096 kB
(1 row)

postgres=# select pg_size_pretty(pg_relation_size('t4'));
pg_size_pretty
----------------
4328 kB
(1 row)

设置小一点能节省15%的存储空间,全表扫描也就能更快一些。而varchar是不受影响的。


文章转载自励志成为PostgreSQL大神,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论