Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


17.9.1.3 InnoDB 表压缩调整

通常情况下,InnoDB 数据存储和压缩中描述的内部优化确保了系统在使用压缩数据时运行良好。然而,因为压缩效率取决于您的数据性质,您可以根据需要影响压缩表性能的决定:

  • 哪些表格要压缩。

  • 使用的压缩页面大小。

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

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

在本节中,您可以找到帮助做出这些架构和配置选择的指南。准备长期测试并将压缩表投入生产时,请查看第 17.9.1.4 节,“运行时监控 InnoDB 表压缩”以了解这些选择在实际情况下的有效性。

一般来说,压缩对包含合理数量字符字符串列的表格效果最好,并且数据被读取的频率远高于写入的频率。由于没有可以预测压缩是否对特定情况有效的方法,因此总是使用特定的工作负载和数据集在代表性配置下进行测试。考虑以下因素来决定哪些表格需要压缩。

压缩数据文件大小的效率关键因素是数据本身的性质。回忆压缩通过在数据块中识别重复字节串来工作。完全随机化的数据是最差的情况。典型数据通常具有重复值,因此可以有效地压缩。字符字符串通常可以很好地压缩,无论它们定义在CHARVARCHARTEXTBLOB列中。另一方面,包含主要二进制数据(整数或浮点数)或已经压缩的数据(例如JPEG或PNG图像)的表格可能不太好地压缩,或者压缩效果很小甚至为零。

您可以选择为每个 InnoDB 表启用压缩。表和所有索引使用相同的(压缩)页面大小。可能的情况是,主键(聚簇)索引,因为它包含了表中的所有列数据,可以比次级索引更好地压缩。在那些有长行的案例中,使用压缩可能会导致长列值被存储在off-page中,如DYNAMIC Row Format所讨论的。这些溢出页面可能会压缩得很好。考虑到这些因素,对于许多应用程序,某些表可能比其他表更好地压缩,您可能发现您的工作负载在只压缩子集表时性能最佳。

要确定是否压缩特定表,请进行实验。您可以使用实现 LZ77 压缩算法的工具(如gzip或 WinZip)对未压缩表的.ibd 文件进行压缩。您可以预期 MySQL 压缩表比文件基于压缩工具少一些,因为 MySQL 根据页面大小(默认 16KB)对数据进行压缩。此外,页面格式还包括一些内部系统数据,这些数据不被压缩。文件基于压缩工具可以检查更大的数据块,并因此可能在大文件中找到更多重复字符串,而 MySQL 在单个页面中找不到。

可以通过将某个表的数据从未压缩的表复制到一个具有相同索引的压缩表(在文件-per-表表空间中)并查看生成的.ibd文件大小来测试压缩。例如:

USE test;
SET GLOBAL innodb_file_per_table=1;
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 对于压缩数据维护的修改日志空间有限。如果更新操作主要更改非索引列或包含BLOB或大字符串的列,并且这些列存储在“off-page”中,那么压缩的开销可能是可接受的。如果表中的唯一变化是使用单调递增主键的INSERT操作,并且没有太多次要索引,那么不需要重新组织和重新压缩索引页。由于 MySQL 可以在压缩页面上“in place”删除行,DELETE操作对表来说相对高效。

对于一些环境,加载数据所需的时间可能与实时检索一样重要,特别是在数据仓库环境中,许多表可能是只读或读写少量。在这种情况下,可能需要支付压缩的代价,即增加加载时间,但如果压缩后的结果是减少磁盘读取次数或存储成本,那么这可能是可接受的。

从根本上讲,压缩在 CPU 时间可用时工作最好。因此,如果您的工作负载是 I/O 绑定的,而不是 CPU 绑定的,您可能会发现压缩可以改善整体性能。在测试应用程序性能时,使用与生产系统计划配置相似的平台进行测试。

从磁盘读取和写入数据库页面是系统性能中最慢的方面。压缩尝试通过使用 CPU 时间来压缩和解压数据,减少 I/O 操作,并且在 I/O 资源相对较scarce的情况下效果最好。

这尤其适用于多用户环境中运行的多核 CPU。当一个压缩表的页面位于内存中,MySQL 通常使用 buffer pool 中的 16KB 内存来存储该页面的未压缩副本。自适应 LRU 算法尝试平衡压缩和未压缩页面之间的内存使用,以考虑工作负载是否在 I/O- bound 或 CPU-bound 模式下运行。即使如此,一配置中 buffer pool 中的内存更多,使用压缩表时通常比内存严重受限的配置运行得更好。

压缩页面大小的最佳设置取决于表和索引中的数据类型和分布。压缩页面大小应该总是大于最大记录大小,以免操作失败,如B-Tree 页面压缩中所述。

如果压缩页面大小设置太大,会浪费一些空间,但这些页面不需要那么频繁地压缩。如果压缩页面大小设置太小,插入或更新操作可能需要时间-consuming 的重新压缩,并且 B-树结点可能需要更频繁地分裂,从而导致数据文件变大和索引效率下降。

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