如何在PostgreSQL13和以下版本中使用lz4压缩文本和二进制数据

从PG14开始,PostgreSQL已经支持LZ4 压缩功能。而PG14之前的版本,其TOAST仅支持一个压缩算法PGLZ(PG内置算法)。众所周知,LZ4比PGLZ的压缩速度快很多。在不要求很高压缩比的场景下,LZ4更适合用于速度敏感型的数据压缩功能。

很多实际场景中,我们为了便于管理,经常将一些大文本和二进制文件存储到数据库里。这时,在不太影响读取速度的时候,存储空间当然是越小越好。很可惜,官方PostgreSQL13和之前的版本不支持LZ4压缩。

那么有没有可能,通过扩展PG的方式来使用lz4压缩功能呢?

答案是可以的。

最近,我就通过开发扩展PG函数的方式实现了lz4压缩和解压缩功能。可以方便的对二进制数据和文本数据进行压缩和解压缩。

我开发了4个自定义函数来进行数据压缩和解压:

# \df
                           List of functions
 Schema |    Name     | Result data type | Argument data types |  Type  
--------+-------------+------------------+---------------------+--------
 public | lz4         | bytea            | bytea bytea         | normal
 public | lz4_utf8    | bytea            | msg text            | normal
 public | un_lz4      | bytea            | bytea bytea         | normal
 public | un_lz4_utf8 | text             | bytea bytea         | normal
(4 rows)
  • lz4:接收bytea类型的数据,返回压缩后的bytea类型数据
  • un_lz4:接收bytea类型的数据,返回解压后的bytea类型数据
  • lz4_utf8:接收utf8编码的文本数据,返回解压后的bytea类型数据
  • un_lz4_utf8:接收bytea类型的数据,返回解压后的utf8编码的文本数据

简单测试一下:

使用lz4压缩

# select lz4('aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,你好,我好,大家好!'::bytea);
                                      lz4                                       
--------------------------------------------------------------------------------
 \x3c0000001f61010009d22ce4bda0e5a5bdefbc8ce688910900c0e5a4a7e5aeb6e5a5bdefbc81
(1 row)

使用un_lz4解压缩,然后convert_from转换成文本

# select convert_from(un_lz4(lz4('aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,你好,我好,大家好!'::bytea)), 'utf8');
                    convert_from                    
----------------------------------------------------
 aaaaaaaaaaaaaaaaaaaaaaaaaaaaa,你好,我好,大家好!
(1 row)

lz4_utf8函数和un_lz4_utf8函数用于在utf8编码环境里,对文本进行lz4压缩和解压缩还原成文本。

以中文绕口令为例。2倍绕口令字节长度:

# select length('八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑;八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑.'::bytea);
 length 
--------
    176
(1 row)

lz4压缩后的字节长度:

# select length(lz4_utf8('八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑;八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑.'));
 length 
--------
     90
(1 row)

压缩并解压缩:

# select un_lz4_utf8(lz4_utf8('八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑;八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑.'));
                                                       un_lz4_utf8                                                        
--------------------------------------------------------------------------------------------------------------------------
 八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑;八百标兵奔北坡 炮兵并排北边跑 炮兵怕把标兵碰 标兵怕碰炮兵跑.
(1 row)

 在数据表格中使用lz4压缩函数。

CREATE TABLE tb_article (
	id serial4 NOT NULL,
	title text NOT NULL,
	content bytea NOT NULL,
	create_time timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP,
	CONSTRAINT tb_disco_exec_pk PRIMARY KEY (id)
);

插入数据,同时用函数进行内容压缩

# insert into tb_article(title, content) values('哈利波特', lz4_utf8('哈利波特哈利波特哈利波特哈利波特哈利波特哈利波特'));
INSERT 0 1

用 * 查询:

# select * from tb_article;
 id |   title   |                         content                          |          create_time          
----+-----------+----------------------------------------------------------+-------------------------------
  1 | 哈利波特  | \x48000000cfe59388e588a9e6b3a2e789b90c002360e6b3a2e789b9 | 2022-03-21 15:25:45.851421+00
  2 | 哈利波特2 | \x48000000cfe59388e588a9e6b3a2e789b90c002360e6b3a2e789b9 | 2022-03-21 15:25:53.897295+00
(2 rows)

查询并用函数对指定字段进行解压:

# select id, title, un_lz4_utf8(content) as content, create_time from tb_article;
 id |   title   |                     content                      |          create_time          
----+-----------+--------------------------------------------------+-------------------------------
  1 | 哈利波特  | 哈利波特哈利波特哈利波特哈利波特哈利波特哈利波特 | 2022-03-21 15:25:45.851421+00
  2 | 哈利波特2 | 哈利波特哈利波特哈利波特哈利波特哈利波特哈利波特 | 2022-03-21 15:25:53.897295+00
(2 rows)

如何安装扩展函数?

目前扩展函数仅支持Linux操作系统。压缩包里有四个目录:

  • pg10.20
  • pg11.15
  • pg12.10
  • pg13.6

每个目录对应PG的一个大版本。编译时是使用的这些具体版本。但应该可以适用于对应的大版本。

每个目录下有三个文件:

  • pg_lz4--0.1.0.sql
  • pg_lz4.control
  • pg_lz4.so

安装时,将pg_lz4.so拷贝到xxx/postgresql/lib/目录下,pg_lz4.control和pg_lz4--0.1.0.sql文件拷贝到xxx/postgresql/share/extension/目录下。

然后,登录到数据库中创建扩展:

CREATE EXTENSION pg_lz4;

也可以指定创建扩展到具体某个schema下

CREATE EXTENSION IF NOT EXISTS pg_lz4 WITH SCHEMA xxxxxx

然后就可以使用了。

下载链接在这里

大家使用过程中有任何问题可以找我处理。

当然,如果有对PG扩展开发有需求的,也可以找我聊聊。

我后续会针对PG扩展出更多的文章和函数库。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Java,可以使用JDBC驱动程序来连接和操作PostgreSQL数据库。要存取PostgreSQL二进制类型bytea,可以使用PreparedStatement对象的setBytes()方法来设置二进制数据,并使用ResultSet对象的getBytes()方法来获取二进制数据以下是一个示例代码,演示了如何存取bytea类型的数据: ```java import java.sql.*; public class PostgresBinaryExample { public static void main(String[] args) throws SQLException { //连接PostgreSQL数据库 String url = "jdbc:postgresql://localhost/test"; String user = "postgres"; String password = "password"; Connection conn = DriverManager.getConnection(url, user, password); //创建表 Statement stmt = conn.createStatement(); String createTable = "CREATE TABLE binary_data (id SERIAL PRIMARY KEY, data BYTEA)"; stmt.executeUpdate(createTable); //插入二进制数据 byte[] binaryData = {0x01, 0x02, 0x03}; PreparedStatement pstmt = conn.prepareStatement("INSERT INTO binary_data (data) VALUES (?)"); pstmt.setBytes(1, binaryData); pstmt.executeUpdate(); //查询二进制数据 ResultSet rs = stmt.executeQuery("SELECT data FROM binary_data"); if (rs.next()) { byte[] retrievedData = rs.getBytes("data"); System.out.println("Retrieved data: " + Arrays.toString(retrievedData)); } //清理资源 rs.close(); pstmt.close(); stmt.executeUpdate("DROP TABLE binary_data"); stmt.close(); conn.close(); } } ``` 在上面的代码,我们首先连接PostgreSQL数据库,然后创建一个名为binary_data的表,其包含一个名为data的bytea列。接着,我们插入一个包含三个字节的二进制数据。最后,我们查询数据并输出到控制台,最后清理资源。 注意,上述代码只是一个示例,实际应用需要更多的错误处理和异常处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值