数据库常用编码和压缩算法介绍

news/2025/11/22 18:36:15/文章来源:https://www.cnblogs.com/dataverse/p/19258333

数据库常用编码和压缩算法介绍

在设计一个优秀的数据库时,存储空间、性能以及资源占用无疑是必须深入考虑的关键因素。这些因素直接关联到数据库的效率、成本以及用户的体验。这里面,编码与压缩也是至关重要的一环。

本文介绍压缩和编码的常用算法,帮助您在使用数据库的时候根据自己的数据表和数据列选择合适的编码格式,优化数据存储结构,节省存储空间,提高数据的读取和查询性能。

1. 编码

1.1 什么是编码?

工作中经常要将图片转成 BASE64 格式方便传输与存储,又或者需要处理音视频减少文件大小,从而提升传输效率,有的时候还会加密数据保障安全。这些都是编码。

维基百科对编码的定义是这样的:编码是信息从一种形式或格式转换为另一种形式的过程;解码则是编码的逆过程。

这种信息转化的过程,一般都会伴随着空间的减少。比如,使用数据字典将一个城市字符串“Beijing”编码映射成 11,存储空间可能就减少了一半。又因为在数据的扫描处理上,字符串的处理时间可能是数字的 2-3 倍以上,所以,如果要对比字段或者给字段排序,那使用数字的性能也全面优于使用字符串,查询性能能够得到较大的提升。

1.2 常见的编码算法

1.2.1 RLE(Run Length Encoding)

RLE算法将连续相同的数据序列编码为“重复次数 + 数据值”组合的形式,以节省存储空间。

比如给定字符串 “AABBBCCCCDDDDD”,经过 RLE 编码后变成了 “2A3B4C5D”。在压缩后的字符串中,RLE 将连续的 “AA” 替换为 “2A”,连续的 “BBB” 替换为 “3B”,连续的 “CCCC” 替换为 “4C”,以此类推。这样,RLE 就压缩了原始字符串,减少了重复字符的存储。

这种编码算法适合用在重复数据较多的场景,比如对图像数据的编码。 因为图像数据通常用 RGB 表示,如(255,0,0)。而图像相邻位置的像素值比较接近,RGB 对应的值相同,比如 [255,0,0;255,0,0;255,0,0;255,0,1;255,0,1 …],那么使用 RLE 就可以表示为 [3:255,0,0; 2:255,0,1],大大减少存储的数据大小。

1.2.2 Delta Encoding

Delta Encoding 是一个基于数值增量的编码算法,它会将数据转换为增量值进行存储,节省存储空间,也可以加快数据的查询速度。

举个例子,给定一个整数的数据序列 a = [10, 14, 18, 22, 26],经过 Delta Encoding 编码后得到的结果是 a’ = [10, 4, 4, 4, 4]。

这里编码的逻辑是,第一个数值保持不变,后续的数值用相对于前一个数值的增量值来表示。因此,原始数据序列中的 [10, 14, 18, 22, 26] 就被转换为 Delta Encoding 后的增量序列 [10, 4, 4, 4, 4]。

这种编码算法并非只能针对数值数据来进行编码。

HBase 里面使用的 Delta Encoding 系列算法,PREFIX、DIFF、FAST_DIFF 等,也能够支持对字符串数据的编码。 用 PREFIX(由 PrefixKeyDeltaEncoder 实现)举个例子。如下图所示,图的上半部分表示一个存储了 4 行数据的表,这个表的行键由两部分组成。

4e2c931093429ae514308ccdaeb2c324

3d3yy188d0fb21dbfd020675e04764ff

第一部分是将用户 ID 反转后补齐 20 位获得的,即行键中的红色部分。这个处理是为了避免热点区间,因为用户 ID 一般是连续的整数,而新用户一般比较活跃,产生的数据较多,所以反转后能够避免连续的新用户全部分到同一个分区或者服务器。

第二部分是一个用 Long.MAX_VALUE 减去当前时间戳,得到的值再补齐 20 位,即行键中的紫色部分。保证得到一个定长的行键,就能方便我们从行键中提取数据,而且最新的数据会排在前面。

再看图的下半部分,是开启编码后存储的数据示例。可以看到,表格里多存储了一列前缀长度,但是行键的位数大大减少了。具体怎么做到的呢?

第 2 行的前缀长 40,表示第 2 行行键的前 40 位跟第 1 行的行键全部一样,只有最后 1 位的 2 跟第 1 行行键不一样。第 3 行行键同样也是只有最后一位 3 跟前一个行键不一样。第 4 行的行键跟前面几行相比,前面 37 位都一样,只有最后 4 位不一样,那就只需要把最后不一样的 4 位存到数据块。

也就是说,如果单从键的长度大小来看,差不多压缩了 60%-70% 的存储空间。 所以,Delta Encoding 特别适合这种按字典序排序的键、值类数据的压缩。比如 HBase 按行键字典序排序。在时序数据库中,数据以时间戳为 key,这些 key 按顺序递增,同时按顺序排列存储。

HBase 默认是没有开启编码的,下面这个建表语句是在 HBase 表中使用 FAST_DIFF 编码的方法。

CREATE 't1', {NAME => 'cf1', DATA_BLOCK_ENCODING => 'FAST_DIFF'}

1.2.3 字典编码(Dictionary Encoding)

字典编码需要构建一个字典表,将数据值映射为字典索引进行存储,减少数据的存储空间,提高压缩比。

比如我们先构建一个城市的字典表,将城市映射成为一个数字,之后在表数据存储时,针对城市的列,我们只需要存储城市的数字编码即可。

字典表:

城市 编码
广州市 10
珠海市 11
佛山市 12

数据表:

姓名 年龄 城市
张三 21 11
李四 24 12

使用字典编码一方面可以节省存储空间,另一方面,如果需要根据城市去过滤查询,使用数字过滤的性能也比字符串要高。

字典编码适合低基数的列,也就是列的 distinct 取值较少的场景。当然,在分布式数据库中,还要考虑字典的全局性与唯一性,以免出现不同节点字典不一致导致数据不一致的情况。StarRocks 就是通过全局字典来解决这个问题的。也就是用一个统一的全局字典来统一所有节点的用来编码的字典表。

总结一下,各种编码方式只要是在合适的场景下使用,就都能节省一定的存储空间,有时候还能提升查询过滤的性能。而且,由于编码后占用空间减小,所以缓存到内存的数据量也变得更多了,同样能够提升性能,但带来的问题就是占用更多的 CPU 资源。

2. 压缩

2.1 什么是压缩?

不是所有的编码都能减少存储空间,比如 Base64 编码会将每 3 个字节的二进制数据转换为 4 个 Base64 字符,反而会增加存储空间。所以在数据库中,通常会结合编码与压缩一起节省存储空间,先将数据编码,然后再压缩。

在计算机技术中,压缩随处可见。它可以分为两种类型。

一种是有损压缩。压缩后的数据会丢失部分信息,但通常丢失的部分不影响数据的完整性。比如针对音频、视频等多媒体数据的压缩,我们常见的 JPEG 图像、MP3 其实都属于有损压缩的技术。

另一种是无损压缩。压缩数据可以完全还原成原始数据,不会损失任何信息。无损压缩通常适用于需要完全保留数据准确性和完整性的情况,数据库领域使用的基本都是无损压缩。

压缩主要是利用消除冗余信息,利用数据的统计特性来减少数据大小、节省存储空间、提升数据传输效率。它会结合不同的编码形式。比如结合字典编码,将重复出现的数据块替换为指向字典中的索引。还有 Huffman 编码,是根据字符出现频率分配不同长度的编码来实现压缩的。出现次数高的字符用短编码表示,出现次数低的字符用长编码表示,从而减少整体长度。

常用的压缩算法包括 Snappy、LZ4、Zstandard、GZip 等,不同的压缩算法会在压缩 / 解压缩速度与压缩比例之间做一个平衡。而且很多压缩算法还能够支持多层压缩,也就是压缩一次后,再进行压缩,这样可以进一步提升压缩比例,但是压缩 / 解压缩时间会相应增加。

这些压缩算法,通常能够压缩 50%-70% 以上的空间,极大地提升了数据的读取与写入速度。而且分布式数据库通常还会对数据进行多副本的备份,压缩后的数据再进行副本的同步,传输数据量也大大减少了,传输备份效率也会提升。

整理了几个数据库所支持的压缩算法,以及这些算法的一些压缩指标。

数据库 支持的压缩算法
HBase 支持 LZO、GZ、SNAPPY、LZ4、ZStandard、BZIP2、LZMA、Brotli 等压缩算法。
默认不开启压缩,支持设置列族级别的压缩。
StarRocks 支持 LZ4、ZStandard、zlib 和 Snappy 压缩算法。
在 StarRocks 中这些算法的压缩率排名是 zlib>Zstandard>LZ4>Snappy。
zlib 拥有较高的压缩比但是会影响到性能,官方建议使用 ZStandard、LZ4。
默认使用 LZ4,支持设置表级别压缩算法。
ClickHouse Clickhouse 把压缩算法、编码混用。
支持的压缩、编码算法很多,比如 LZ4、ZStandard、Delta、Gorilla 等。
默认使用 LZ4,支持设置列级别的压缩算法。

下面是这 3 个分布式数据库建表时启用编码与压缩的方法。

# HBase 启用压缩
CREATE 't1',{NAME => 'cf1', COMPRESSION => 'SNAPPY'},{NAME => 'cf2', COMPRESSION => 'GZ'}# Starrocks 启用压缩
CREATE TABLE `t1`
(`id`   INT(11) NOT NULL,`key` CHAR(200) NULL ,`value` CHAR(200) NULL
) ENGINE = OLAP 
UNIQUE KEY(`id`)
DISTRIBUTED BY HASH(`id`)
PROPERTIES ("compression" = "ZSTD"
);# Clickhouse 启用压缩
CREATE TABLE t3
(dt Date CODEC(ZSTD),ts DateTime CODEC(LZ4HC),float_value Float32 CODEC(NONE),double_value Float64 CODEC(LZ4HC(9)),value1 Float32 CODEC(Delta, ZSTD),value2 Float32 CODEC(Gorilla)
) ENGINE = MergeTree()
PARTITION BY toYYYYMM(dt)
ORDER BY (dt, ts);

这 3 个分布式数据库都支持 LZ4 算法,而且其中两个都把它当做默认的压缩算法,Clickhouse 则最为灵活,可以设置列级别的压缩算法。而 HBase 默认是不启用编码与压缩的,用户可以基于自己的数据选用一个合适的编码压缩算法,一般都会提升整体的性能。

2.2 压缩算法指标

不同的压缩算法,在不同场景、不同类型数据集、不同机器配置下表现差异较大,可以从这个压缩性能基准测试网站看到各种压缩算法的压缩比率、压缩速度、解压速度的一个对比。

https://quixdb.github.io/squash-benchmark/#results-table

以下是一段生成 parquet 文件并进行压缩的代码:

import pyarrow as pa
import pyarrow.parquet as pq
import random
import time# 创建一个员工表,包含员工ID、部门ID、薪资 3列
data = {'employ_id': [],'dep_no': [],'salary': [],
}
# 随机生成 10000000 个员工数据
for i in range(10000000):data['employ_id'].append('NO' + str(i + 1))  # 员工ID从1开始递增data['dep_no'].append(random.randint(1, 10))  # 部门ID随机取值范围为1-10data['salary'].append(random.randint(1000, 10000))  # 薪资随机取值范围为1000-10000
table = pa.table(data)# 不压缩写入
start_time = time.time()
pq.write_table(table, 'employee_no_compress.parquet', compression=None)
end_time = time.time()
execution_time = (end_time - start_time) * 1000
print(f"不压缩执行时间: {execution_time} 毫秒")# 使用 SNAPPY 压缩写入
start_time = time.time()
pq.write_table(table, 'employee_snappy.parquet', compression='SNAPPY')
end_time = time.time()
execution_time = (end_time - start_time) * 1000
print(f"SNAPPY压缩执行时间: {execution_time} 毫秒")# 使用 LZ4 压缩写入
start_time = time.time()
pq.write_table(table, 'employee_lz4.parquet', compression='LZ4')
end_time = time.time()
execution_time = (end_time - start_time) * 1000
print(f"LZ4压缩执行时间: {execution_time} 毫秒")

代码中随机生成了 1000 万行员工数据,然后分别不压缩、使用 Snappy 压缩、使用 LZ4 压缩后写入 Parquet 文件。输出结果如下所示。

不压缩执行时间: 512.6681327819824 毫秒
SNAPPY压缩执行时间: 579.6384811401367 毫秒
LZ4压缩执行时间: 596.900224685669 毫秒

同时输出文件大小分别为:不压缩 = 153.9M、Snappy 压缩 = 73.3M、LZ4 压缩 = 66.7M。

可以看到,压缩率 LZ4 相对更高,Snappy 则性能稍优。

但压缩也不是“放之四海而皆准”的。在一些高性能系统中,如果大量使用压缩,将会占用较多的 CPU 资源,进而有可能导致系统响应性能下降。而且有时候数据需要解压后才能查询过滤,这对读性能又是一个不利的因素。

3. 总结

本文介绍了编码与压缩的原理和用途,包括节省存储空间,通过优化数据对比和过滤让相同的内存下能够缓存更多的数据,从而提升数据传输、读写的性能。当然,带来的副作用是对 CPU 资源的占用。

比如 HBase2.0 之前有一个叫做 PREFIX_TREE 的编码算法,某些情况下甚至直接导致 CPU 占用 100%,不过在 HBase2.0 之后的版本,这个编码算法被弃用了。

不同的编码与压缩的方式基本是在平衡效率与性能,用户需要根据使用场景进行取舍。比如在时序数据集下可能就适合用 Delta 编码压缩的方式。低基数的全球地址表就适合使用字典编码等。本文也提供了一个使用自己数据集来测试不同压缩方式的例子,可以用来判断哪个压缩算法更合适现有数据集。

编码与压缩是数据库高性能的一个重要因素,LZ4、Snappy、ZStandard 是在数据库引擎中支持较广的压缩方式,一般情况下使用默认的编码压缩会取得较好的性能平衡,知道调整这些编码与压缩算法的方法,可以让用户根据自己的数据集的进行一些性能调优。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/973326.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

onenote复制纯文本的方法

onenote在复制文本到其他地方进行粘贴后,经常会变成图片,以下是解决办法: 方法一: 1. 使用win + Q 或者 win + S 复制后再粘贴 方法二: 2. 复制到word中 方法三: 3. 上使用Ditto剪切板增强软件3.1 复制后 使用Al…

hive sql开发有啥优势

Hive SQL开发相较于传统的SQL开发,具有以下显著优势:灵活的数据模型:Hive支持非结构化和半结构化数据,如文本文件、图像、视频等。这使得它能够处理更多种类的数据,满足更广泛的业务需求。 大规模数据处理能力:H…

hive sql开发怎样避免错误

在Hive SQL开发中,避免错误的方法有很多。以下是一些建议:熟悉Hive SQL语法:确保你对Hive SQL的语法有深入的了解。这将帮助你避免编写错误的查询语句。 使用正确的数据类型:在定义表和列时,确保使用正确的数据类…

完整教程:C语言标准库完全指南

完整教程:C语言标准库完全指南pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco&quo…

fedora43使用incus启动虚拟机报错: qemu-system-x86_64: Unknown audio driver spice

操作系统版本: Fedora 43 (Server Edition) linux内核版本: 6.17.1-300.fc43.x86_64 incus版本: 6.18 qemu-system-x86_64版本: QEMU emulator version 10.1.2 (qemu-10.1.2-1.fc43) 问了chatgpt和结合github上相关iss…

hive sql开发常见错误是啥

Hive SQL开发中常见的错误有很多种,以下是一些例子:语法错误:这是最常见的错误类型,可能是由于拼写错误、缺少必要的符号或者使用了错误的命令。例如,如果你忘记了在SELECT语句后加上分号,就会收到一个语法错误。…

hive sql开发学习资料在哪

Hive SQL开发学习资料可以从多个途径获取,以下是一些建议的资源:官方文档:Apache Hive的官方网站提供了详细的文档,包括用户指南、开发者指南、API文档等。这些文档可以帮助你了解Hive的基本概念、功能和使用方法。…

测试经验分享,登录功能+购物车+限时秒杀(测试点)汇总 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

解决 Android 项目升级 composeBom 2025.11.01 版本后,出现 import androidx.compose.material3.Icon 找不到的问题

参考豆包 https://developer.android.google.cn/develop/ui/compose/bom/bom-mapping?hl=zh-cn https://developer.android.google.cn/jetpack/androidx/releases/compose-material3?hl=zh-cn https://developer.and…

完整教程:《工业之心:Blender 工业场景解构》

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

深入解析:pip 的包下载之后存放在哪?

深入解析:pip 的包下载之后存放在哪?2025-11-22 18:16 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !…

图书馆管理系统需求改进和系统设计

图书馆管理系统需求规划设计书这个作业属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/这个作业要求在哪里 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/h…

SGD 、Momentum 、Adam

深度学习中最核心的三种优化算法或优化策略:SGD (随机梯度下降)、Momentum (动量) 策略,以及 Adam (自适应矩估计) 优化器。 下面是它们的核心原理、优势和关系总结:优化器/策略总结对比名称 类型 核心机制 主要解决…

P22_损失函数与反向传播

P22_损失函数与反向传播22.1损失函数的作用计算实际输出和目标之间的差距 为我们更新输出提供一定的依据(反向传播)22.2几种官方文档中的损失函数 打开torch.nn—Loss Functions: 【注意:损失函数只能处理float类型…

团队作业3-需求改进系统设计

团队作业3-综合报告(Alpha阶段)项目 详情这个作业属于哪个课程 计科23级12班这个作业要求在哪里 作业要求链接这个作业的目标 对现有项目进行设计和需求&原型改进,进行 Alpha 阶段任务分配队名与队员: MCoder,…

完整教程:Opencv(一): 用Opencv了解图像

完整教程:Opencv(一): 用Opencv了解图像pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "M…

docker compose插件安装

参考链接 在 Ubuntu 22.04 中,我们需要从官方 Docker 仓库安装 Docker Compose 插件。首先,让我们确保我们具备必要的先决条件: sudo apt-get install -y ca-certificates curl gnupg现在,添加 Docker 的官方 GPG …

完整教程:树与二叉树的奥秘全解析

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

C#扩展成员全面解析:从方法到属性的演进

本文详细介绍了C#中扩展成员的发展历程,从传统的扩展方法到C# 14中的扩展属性和索引器,通过具体代码示例展示如何更优雅地扩展现有类型功能。C#扩展成员:你需要知道的一切 扩展方法在C#中已经存在很长时间。它们允许…

多机elasticsearch集群部署,超详细教程

假设我们有三台机器,172.24.52.209,172.24.52.210,172.24.52.211。 用户名xjw 三台机器都创建文件夹/home/xjw/docker/learning/elasticsearch,和/home/xjw/docker/learning/kibana,learning为项目名 mkdir -p /h…