Documentation Home
MySQL 8.0 参考手册  / 第 15 章 InnoDB 存储引擎  / 15.9 InnoDB 表和页压缩  /  14.9.3 调整 InnoDB 表的压缩

14.9.3 调整 InnoDB 表的压缩

大多数情况下, InnoDB 数据存储和压缩中描述的内部优化可确保系统在压缩数据的情况下运行良好。但是,由于压缩效率取决于数据的性质,您可以做出影响压缩表性能的决定:

  • 要压缩哪些表。

  • 使用什么压缩页面大小。

  • 是否根据运行时性能特征调整缓冲池的大小,例如系统花费在压缩和解压缩数据上的时间量。工作负载更像是 数据仓库 (主要是查询)还是 OLTP系统(查询和DML的混合体)。

  • 如果系统对压缩表执行 DML 操作,并且数据分布方式导致运行时发生代价高昂的 压缩失败,您可能需要调整其他高级配置选项。

使用本节中的指南来帮助做出这些体系结构和配置选择。当您准备好进行长期测试并将压缩表投入生产时,请参阅 第 14.9.4 节,“在运行时监视 InnoDB 表压缩”,了解在实际条件下验证这些选择有效性的方法。

何时使用压缩

通常,压缩在包含合理数量的字符串列且数据读取频率远高于写入频率的表上效果最佳。由于无法保证预测压缩是否有益于特定情况的方法,因此请始终使用 在代表性配置上运行的特定工作负载和数据集进行测试。在决定压缩哪些表时,请考虑以下因素。

数据特征和压缩

压缩数据文件大小的压缩效率的一个关键决定因素是数据本身的性质。回想一下,压缩是通过识别数据块中重复的字节串来工作的。完全随机化的数据是最坏的情况。典型数据通常具有重复值,因此可以有效压缩。字符串通常可以很好地压缩,无论是在CHAR、还是列VARCHAR中 定义。另一方面,主要包含二进制数据(整数或浮点数)或之前压缩过的数据(例如JPEGPNG图像)的表格通常可能无法很好地压缩,显着压缩或根本无法压缩。 TEXTBLOB

您选择是否为每个 InnoDB 表打开压缩。一个表及其所有索引使用相同的(压缩的) 页面大小。可能是主键 (聚集)索引(包含表的所有列的数据)比二级索引更有效地压缩。对于那些有长行的情况,使用压缩可能会导致长列值存储在 页外,如 动态行格式中所述. 那些溢出页面可能压缩得很好。考虑到这些因素,对于许多应用程序,某些表比其他表压缩更有效,您可能会发现您的工作负载仅在压缩表的子集时性能最佳。

要确定是否压缩特定表,请进行实验。通过在未压缩表的.ibd 文件gzip副本上使用实现 LZ77 压缩的实用程序(例如或 WinZip),您可以粗略估计数据的压缩效率。与基于文件的压缩工具相比,MySQL 压缩表的压缩率更低,因为 MySQL 根据页面大小以块的形式压缩数据, 默认为 16KB。除用户数据外,页面格式还包括一些未压缩的内部系统数据。基于文件的压缩实用程序可以检查更大的数据块,因此可能会在一个巨大的文件中找到比 MySQL 在单个页面中找到的更多的重复字符串。

在特定表上测试压缩的另一种方法是将一些数据从未压缩的表复制到类似的压缩表(具有所有相同的索引)并查看生成.ibd文件的大小。例如:

USE test;
SET GLOBAL innodb_file_per_table=1;
SET GLOBAL innodb_file_format=Barracuda;
SET GLOBAL autocommit=0;

-- Create an uncompressed table with a million or two rows.
CREATE TABLE big_table AS SELECT * FROM information_schema.columns;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
INSERT INTO big_table SELECT * FROM big_table;
COMMIT;
ALTER TABLE big_table ADD id int unsigned NOT NULL PRIMARY KEY auto_increment;

SHOW CREATE TABLE big_table\G

select count(id) from big_table;

-- Check how much space is needed for the uncompressed table.
\! ls -l data/test/big_table.ibd

CREATE TABLE key_block_size_4 LIKE big_table;
ALTER TABLE key_block_size_4 key_block_size=4 row_format=compressed;

INSERT INTO key_block_size_4 SELECT * FROM big_table;
commit;

-- Check how much space is needed for a compressed table
-- with particular compression settings.
\! ls -l data/test/key_block_size_4.ibd

这个实验产生了以下数字,当然这些数字可能会因您的表结构和数据而有很大差异:

-rw-rw----  1 cirrus  staff  310378496 Jan  9 13:44 data/test/big_table.ibd
-rw-rw----  1 cirrus  staff  83886080 Jan  9 15:10 data/test/key_block_size_4.ibd

要查看压缩对于您的特定工作负载 是否有效 :

数据库压缩与应用程序压缩

决定是压缩应用程序中的数据还是表中的数据;不要对同一数据使用两种类型的压缩。当您压缩应用程序中的数据并将结果存储在压缩表中时,额外节省空间的可能性极小,而且双重压缩只会浪费 CPU 周期。

在数据库中压缩

启用后,MySQL 表压缩是自动的,适用于所有列和索引值。列仍然可以使用诸如 之类的运算符进行测试LIKE,并且排序操作仍然可以使用索引,即使索引值被压缩也是如此。由于索引通常占数据库总大小的很大一部分,因此压缩可以显着节省存储、I/O 或处理器时间。压缩和解压缩操作发生在数据库服务器上,这可能是一个功能强大的系统,其大小可以处理预期的负载。

在应用程序中压缩

如果在应用程序中压缩数据(例如文本),在将其插入数据库之前,您可以通过压缩某些列而不压缩其他列来节省压缩效果不佳的数据的开销。这种方法使用 CPU 周期在客户端而不是数据库服务器上进行压缩和解压缩,这可能适用于具有许多客户端的分布式应用程序,或者客户端计算机有空闲 CPU 周期的情况。

混合方法

当然,可以结合这些方法。对于某些应用程序,使用一些压缩表和一些未压缩表可能是合适的。最好从外部压缩一些数据(并将其存储在未压缩的表中)并允许 MySQL 压缩应用程序中的(某些)其他表。一如既往,前期设计和实际测试对于做出正确的决定很有价值。

工作负载特征和压缩

除了选择要压缩的表(以及页面大小)之外,工作负载是性能的另一个关键决定因素。 如果应用程序以读取而不是更新为主,则在索引页用完MySQL 为压缩数据维护的每页修改日志”的空间后,需要重新组织和重新压缩的页面就会减少。如果更新主要更改非索引列或包含 BLOBs 或恰好存储在 页外的大字符串的列,则压缩开销可能是可以接受的。如果对表的唯一更改是 INSERTs使用单调递增的主键,二级索引很少,几乎不需要重新组织和压缩索引页。由于 MySQL 可以 通过修改未压缩的数据 来删除标记”并就地删除压缩页面上的行 ,DELETE因此对表的操作相对高效。

对于某些环境,加载数据所花费的时间可能与运行时检索一样重要。特别是在数据仓库环境中,许多表可能是只读的或以读为主。在这些情况下,以增加加载时间为压缩代价可能是可以接受的,也可能是不可接受的,除非由此带来的减少磁盘读取或存储成本的节省是显着的。

从根本上说,当 CPU 时间可用于压缩和解压缩数据时,压缩效果最佳。因此,如果您的工作负载受 I/O 限制,而不是受 CPU 限制,您可能会发现压缩可以提高整体性能。当您使用不同的压缩配置测试您的应用程序性能时,请在类似于生产系统的计划配置的平台上进行测试。

配置特征和压缩

从磁盘读取和写入数据库 页面是系统性能最慢的方面。压缩试图通过使用 CPU 时间来压缩和解压缩数据来减少 I/O,并且当 I/O 与处理器周期相比是一种相对稀缺的资源时最有效。

在具有快速多核 CPU 的多用户环境中运行时,情况尤其如此。当压缩表的页面在内存中时,MySQL 通常在缓冲池中使用额外的内存,通常为 16KB,用于页面的未压缩副本。自适应 LRU 算法试图平衡压缩页面和未压缩页面之间的内存使用,以考虑工作负载是以 I/O 绑定还是 CPU 绑定方式运行。尽管如此,与内存高度受限的配置相比,使用压缩表时,具有更多内存专用于缓冲池的配置往往运行得更好。

选择压缩页面大小

压缩页面大小的最佳设置取决于表及其索引包含的数据类型和分布。压缩页面大小应始终大于最大记录大小,否则操作可能会失败,如 Compression of B-Tree Pages中所述。

将压缩页面大小设置得太大会浪费一些空间,但不必经常压缩页面。如果压缩页面大小设置得太小,插入或更新可能需要耗时的重新压缩,并且 B 树节点可能不得不更频繁地拆分,从而导致更大的数据文件和更低的索引效率。

通常,您将压缩页面大小设置为 8K 或 4K 字节。鉴于 InnoDB 表的最大行大小约为 8K, KEY_BLOCK_SIZE=8通常是一个安全的选择。