压缩编码 - Amazon Redshift

从补丁 198 开始,Amazon Redshift 将不再支持创建新的 Python UDF。现有的 Python UDF 将继续正常运行至 2026 年 6 月 30 日。有关更多信息,请参阅博客文章

压缩编码

c压缩编码指定在向表中添加行时应用到数据值列的压缩类型。

ENCODE AUTO 是表的默认设置。将表设置为 ENCODE AUTO 时,Amazon Redshift 会自动管理表中所有列的压缩编码。有关更多信息,请参阅CREATE TABLEALTER TABLE

但是,如果为表中的任何列指定压缩编码,则表不再设置为 ENCODE AUTO。Amazon Redshift 不再自动管理表中所有列的压缩编码。

使用 CREATE TABLE 时,为表中的任何列指定压缩编码时会禁用 ENCODE AUTO。如果禁用了 ENCODE AUTO,Amazon Redshift 会自动为您未指定 ENCODE 类型的列分配压缩编码,如下所示:

  • 为定义为排序键的列分配 RAW 压缩。

  • 为定义为 BOOLEAN、REAL 或 DOUBLE PRECISION 数据类型的列分配 RAW 压缩。

  • 定义为 SMALLINT、INTEGER、BIGINT、DECIMAL、DATE、TIMESTAMP 或 TIMESTAMPTZ 数据类型的列分配了 AZ64 压缩。

  • 定义为 CHAR 或 VARCHAR 数据类型的列分配了 LZO 压缩。

在创建表后,您可以使用 ALTER TABLE 更改表的编码。如果您使用 ALTER TABLE 禁用 ENCODE AUTO,Amazon Redshift 将不再自动管理列的压缩编码。所有列都将保留您禁用 ENCODE AUTO 时的压缩编码类型,直到您更改它们或再次启用 ENCODE AUTO。

Amazon Redshift 支持以下压缩编码:

Raw

原始编码是指定为排序键的列和定义为 BOOLEAN、REAL 或 DOUBLE PRECISION 数据类型的列的默认编码。使用原始编码时,数据以原始、未压缩的形式存储。

AZ64

AZ64 是 Amazon 的专有压缩编码算法,旨在实现高压缩率和改进的查询处理。AZ64 算法的核心是压缩较小的数据值组,并使用单指令多数据 (SIMD) 指令实现并行处理。使用 AZ64 为数字、日期和时间数据类型实现显著的存储节省和高性能。

使用带有以下数据类型的 CREATE TABLE 和 ALTER TABLE 语句定义列时,您可以使用 AZ64 作为压缩编码:

  • SMALLINT

  • INTEGER

  • BIGINT

  • DECIMAL

  • DATE

  • TIMESTAMP

  • TIMESTAMPTZ

Byte-dictionary

在字节词典编码中,会为磁盘上的每个列值数据块创建单独的唯一值词典。(一个 Amazon Redshift 磁盘数据块占用 1 MB 的空间。) 词典最多包含 256 个单字节值,它们作为原始数据值的索引存储。如果单个数据块中存储的值多于 256 个,则多余的值会以原始、未压缩的形式写入该数据块中。针对每个磁盘数据块重复这一过程。

此编码对低基数字符串列非常有效。如果列的数据域少于 256 个唯一值,则该编码是最佳的编码。

如果列使用通过 BYTEDICT 编码的字符串数据类型(CHAR 和 VARCHAR),Amazon Redshift 会直接对压缩数据进行矢量化扫描和谓词评估。这些扫描使用特定于硬件的单指令和多数据 (SIMD) 指令实现并行处理。这大大加快了扫描字符串列的速度。当 CHAR/VARCHAR 列包含长字符串时,字节词典编码的空间效率尤其高。

假设某个表包含数据类型为 CHAR(30) 的 COUNTRY 列。在加载数据时,Amazon Redshift 会创建词典并使用索引值填充 COUNTRY 列。该词典包含已建立索引的唯一值,而表本身则只包含相应值的下标(只占一个字节)。

注意

固定长度字符列存储有尾随空格。因此,对 CHAR(30) 列使用字节词典编码时,每个压缩值可节约 29 个字节的存储空间。

下表列出了 COUNTRY 列的词典。

唯一数据值 词典索引 大小(固定长度,每个值 30 个字节)
England 0 30
United States of America 1 30
Venezuela 2 30
Sri Lanka 3 30
Argentina 4 30
Japan 5 30
总计 180

下表列出了 COUNTRY 列中的值。

原始数据值 原始大小(固定长度,每个值 30 个字节) 压缩值(索引) 新的大小(字节)
England 30 0 1
England 30 0 1
United States of America 30 1 1
United States of America 30 1 1
Venezuela 30 2 1
Sri Lanka 30 3 1
Argentina 30 4 1
Japan 30 5 1
Sri Lanka 30 3 1
Argentina 30 4 1
总计 300 10

本示例中的总计压缩大小按照如下方式计算:词典中存储着 6 个不同的条目 (6 * 30 = 180),表包含 10 个 1 字节的压缩值,总共占用 190 个字节。

Delta

对于日期时间列,增量编码非常有用。

增量编码通过记录列中各个相邻值之间的差异来压缩数据。这种差异记录在磁盘上每个列值数据块的单独词典中。(一个 Amazon Redshift 磁盘数据块占用 1 MB 的空间。) 例如,假设列中包含 10 个从 1 到 10 的整数。第一个存储为 4 字节整数(加上 1 字节标记)。接下来的九个都存储为值为 1 的字节,表示它比前一个值大 1。

增量编码有两个版本:

  • DELTA 使用 1 字节的值(8 位整数)记录差值。

  • DELTA32K 使用 2 字节值(16 位整数)记录差值。

如果列中的大多数值可用单字节压缩,则 1 字节的变化会非常高效。但是,如果增量较大,则在最坏情况下,这种编码会比存储未压缩数据的效率还低。相似的逻辑也适用于 16 位版本。

如果两个值的差值超出 1 字节范围 (DELTA) 或 2 字节范围 (DELTA32K),则存储完整的原始值,并包含一个前置的 1 字节标志。1 字节的范围为 -127 到 127;2 字节的范围为 -32K 到 32K。

下表显示了对数值列应用增量编码的原理。

原始数据值 原始大小(字节) 差值(增量) 压缩值 压缩大小(字节)
1 4 1 1+4(标志 + 实际值)
5 4 4 4 1
50 4 45 45 1
200 4 150 150 1+4(标志 + 实际值)
185 4 -15 -15 1
220 4 35 35 1
221 4 1 1 1
总计 28 15
LZO

LZO 编码提供非常高的压缩率,且具有不错的性能。LZO 编码特别适合用于存储非常长的字符串的 CHAR 和 VARCHAR 列。对于自由格式文本(如产品描述、用户评论或 JSON 字符串),它们特别适合使用。

Mostly

当列的数据类型大于大多数存储值所需时,Mostly 编码会很有用。通过为此类型的列指定 Mostly 编码,您可以将该列中的大部分值压缩成较小的标准存储大小。无法压缩的剩余值以原始形式存储。例如,您可以将 16 位列(如 INT2 列)压缩为 8 位存储。

一般说来,Mostly 编码适用于以下数据类型:

  • SMALLINT/INT2(16 位)

  • INTEGER/INT(32 位)

  • BIGINT/INT8(64 位)

  • DECIMAL/NUMERIC(64 位)

请选择适当的 Mostly 编码版本,以契合列的数据类型大小。例如,对于 16 位整数列,可以应用 MOSTLY8。不允许对 16 位数据类型列应用 MOSTLY16 或对 32 位数据类型列应用 MOSTLY32。

当列中相对较多的值无法压缩时,大部分编码的效率可能比不压缩的效率还低。在将其中一个编码应用于列之前,请执行检查。您打算现在加载(以及未来可能加载)的大多数值应该适合下表所示的范围。

编码 压缩的存储大小 可压缩的值的范围(超出范围的值以原始形式存储)
MOSTLY8 1 字节(8 位) -128 到 127
MOSTLY16 2 字节(16 位) -32768 到 32767
MOSTLY32 4 字节(32 位) -2147483648 到 +2147483647
注意

对于小数值,忽略小数点以确定该值是否适合范围。例如,将 1234.56 视为 123456,因此,可压缩到 MOSTLY32 列中。

例如,VENUE 表中的 VENUEID 列定义为原始整数列,这意味着其值占用 4 个字节的存储。但是,该列中值的当前范围为 0309。因此,为 VENUEID 使用 MOSTLY16 编码并重新创建和重新加载该表可将该列中每个值的存储缩减为 2 个字节。

如果另一个表引用的 VENUEID 值主要处于 0 到 127 的范围内,则可以将该外键列编码为 MOSTLY8。在做出选择之前,请对引用表数据运行多个查询,以确定大多数值是处于 8 位、16 位还是 32 位范围内。

下表显示了使用 MOSTLY8、MOSTLY16 和 MOSTLY32 编码时特定数值的压缩大小:

原始值 原始 INT 或 BIGINT 大小(字节) MOSTLY8 压缩大小(字节) MOSTLY16 压缩大小(字节) MOSTLY32 压缩大小(字节)
1 4 1 2 4
10 4 1 2 4
100 4 1 2 4
1000 4 与原始数据大小相同 2 4
10000 4 2 4
20000 4 2 4
40000 8 与原始数据大小相同 4
100000 8 4
2000000000 8 4
Run length

运行长度编码将连续反复出现的值替换为一个包含该值及连续出现次数(连续出现长度)的令牌。系统会为磁盘上的每个列数值数据块创建单独的唯一值词典。(一个 Amazon Redshift 磁盘数据块占用 1 MB 的空间。) 该编码最适合数据值经常反复连续出现的表,例如,当表按这些值排序时。

例如,假设某个大型维度表中的列具有可预测的小型域,如可能值不足 10 个的 COLOR 列。即使没有对数据进行排序,这些值很可能会在整个表中按长序列排列。

我们不建议对指定为排序键的任何列应用运行长度编码。当数据块中包含相似的行数时,范围限制扫描可更好地执行。如果排序键列的压缩率远高于同一查询中的其他列,则范围限制扫描的执行效率可能会很差。

下表使用 COLOR 列的示例来讲解运行长度编码的工作原理。

原始数据值 原始大小(字节) 压缩值(标记) 压缩大小(字节)
Blue 4 {2,Blue} 5
Blue 4 0
Green 5 {3,Green} 6
Green 5 0
Green 5 0
Blue 4 {1,Blue} 5
Yellow 6 {4,Yellow} 7
Yellow 6 0
Yellow 6 0
Yellow 6 0
总计 51 23
Text255 and Text32k

Text255 和 text32k 编码对于压缩经常出现相同单词的 VARCHAR 列非常有用。系统会为磁盘上的每个列数值数据块创建单独的唯一单词词典。(一个 Amazon Redshift 磁盘数据块占用 1 MB 的空间。) 词典包含列中前 245 个唯一的单词。在磁盘上,这些单词会被替换成代表这 245 个值之一的 1 字节索引值,词典中未表示的任意单词以未压缩方式存储。这一过程会针对每个 1MB 磁盘数据块重复执行。如果索引词在列中的出现频度很高,则该列会产生较高的压缩率。

text32k 编码的原理也是如此,但每个数据块的词典并不捕获特定数量的单词。该词典为其找到的每个唯一单词编制索引,直到组合条目达到 32K 的长度(减去一些开销)。索引值用两个字节存储。

例如,我们来考虑一下 VENUE 表中的 VENUENAME 列。该列中重复出现 ArenaCenterTheatre 之类的单词,且很可能出现在每个数据块中的前 245 个单词中(如果应用 text255 压缩的话)。如果是这样,该列将受益于压缩。因为每当这些单词出现时,它们将只占用 1 字节的存储空间(而不是相对应的 5、6 或 7 个字节)。

ZSTD

Zstandard (ZSTD) 编码提供高压缩率,而且在不同数据集中都有极佳性能。ZSTD 特别适用于存储多种长、短字符串(例如产品描述、用户评论、日志和 JSON 字符串)的 CHAR 和 VARCHAR 列。某些算法(如 Delta 编码或 Mostly 编码)可能会比不压缩占用更多的存储空间,而 ZSTD 则不太可能增加磁盘使用量。

ZSTD 支持 SMALLINT、INTEGER、BIGINT、DECIMAL、REAL、DOUBLE PRECISION、BOOLEAN、CHAR、VARCHAR、DATE、TIMESTAMP 和 TIMESTAMPTZ 数据类型。

下表列出了支持的压缩编码和支持该编码的数据类型。

编码类型 CREATE TABLE 和 ALTER TABLE 中的关键字 数据类型
Raw(无压缩) RAW 所有
AZ64 AZ64 SMALLINT、INTEGER、BIGINT、DECIMAL、DATE、TIMESTAMP、TIMESTAMPTZ
字节词典 BYTEDICT SMALLINT、INTEGER、BIGINT、DECIMAL、REAL、DOUBLE PRECISION、CHAR、VARCHAR、DATE、TIMESTAMP、TIMESTAMPTZ
Delta

DELTA

DELTA32K

SMALLINT、INT、BIGINT、DATE、TIMESTAMP、DECIMAL

INT、BIGINT、DATE、TIMESTAMP、DECIMAL

LZO LZO SMALLINT、INTEGER、BIGINT、DECIMAL、CHAR、VARCHAR、DATE、TIMESTAMP、TIMESTAMPTZ、SUPER
Mostlyn

MOSTLY8

MOSTLY16

MOSTLY32

SMALLINT、INT、BIGINT、DECIMAL

INT、BIGINT、DECIMAL

BIGINT、DECIMAL

Run-length RUNLENGTH SMALLINT、INTEGER、BIGINT、DECIMAL、REAL、DOUBLE PRECISION、BOOLEAN、CHAR、VARCHAR、DATE、TIMESTAMP、TIMESTAMPTZ
文本

TEXT255

TEXT32K

仅 VARCHAR

仅 VARCHAR

Zstandard ZSTD SMALLINT、INTEGER、BIGINT、DECIMAL、REAL、DOUBLE PRECISION、BOOLEAN、CHAR、VARCHAR、DATE、TIMESTAMP、TIMESTAMPTZ、SUPER