通常,InnoDB 数据存储和压缩中描述的内部优化可以确保系统在压缩数据的情况下良好运行。但是,由于压缩效率取决于数据的性质,因此您可以做出影响压缩表性能的决定
使用本节中的指南来帮助做出这些架构和配置选择。当您准备好进行长期测试并将压缩表投入生产时,请参阅 第 17.9.1.4 节,“监控 InnoDB 表压缩的运行时”,了解如何在实际环境中验证这些选择的有效性。
何时使用压缩
一般而言,压缩最适合包含合理数量的字符字符串列并且读取数据远比写入数据频繁的表。由于无法保证预测压缩是否对特定情况有利,因此请始终在代表性配置上运行特定 工作负载 和数据集进行测试。在决定要压缩哪些表时,请考虑以下因素。
数据特征和压缩
压缩在减小数据文件大小方面效率的关键决定因素是数据的性质本身。请记住,压缩通过识别数据块中重复的字节字符串来实现。完全随机的数据是最糟糕的情况。典型数据通常具有重复值,因此可以有效压缩。字符字符串通常可以很好地压缩,无论是在 CHAR
、VARCHAR
、TEXT
还是 BLOB
列中定义。另一方面,包含大量二进制数据(整数或浮点数)或先前压缩的数据(例如JPEG或PNG图像)的表通常不会有效地压缩,或者根本不会压缩。
您可以选择是否为每个 InnoDB 表启用压缩。表及其所有索引使用相同的(压缩) 页大小。可能是 主键(聚集)索引包含表所有列的数据,并且比二级索引压缩得更有效。对于那些包含长行的案例,使用压缩可能会导致长列值被存储在 “页面外”,如 DYNAMIC 行格式 中所述。这些溢出页面可能压缩得很好。考虑到这些因素,对于许多应用程序而言,某些表比其他表压缩得更有效,您可能会发现您的工作负载仅在压缩部分表时才能获得最佳性能。
要确定是否压缩特定表,请进行实验。您可以使用实现 LZ77 压缩的工具(例如 gzip
或 WinZip)对未压缩表的 .ibd 文件 的副本进行压缩,从而粗略估计您的数据可以压缩的效率。与基于文件的压缩工具相比,MySQL 压缩表的压缩率会更低,因为 MySQL 基于 页面大小(默认值为 16KB)按块压缩数据。除了用户数据,页面格式还包含一些未压缩的内部系统数据。基于文件的压缩实用程序可以检查更大的数据块,因此在大型文件中找到重复字符串的可能性比 MySQL 在单个页面中找到的可能性更大。
测试特定表压缩的另一种方法是将未压缩表中的部分数据复制到具有相同索引的类似压缩表中(在 每个表一个文件 表空间中),然后查看生成的 .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
要查看压缩对特定 工作负载 是否有效
对于简单的测试,请使用没有其他压缩表的 MySQL 实例,并针对信息架构
INNODB_CMP
表运行查询。对于涉及多个压缩表的更复杂的测试,请针对信息架构
INNODB_CMP_PER_INDEX
表运行查询。因为INNODB_CMP_PER_INDEX
表中的统计信息收集成本很高,所以您必须在查询该表之前启用配置选项innodb_cmp_per_index_enabled
,并且您可能将此类测试限制在开发服务器或非关键副本服务器上。对您正在测试的压缩表运行一些典型的 SQL 语句。
通过查询
INFORMATION_SCHEMA.INNODB_CMP
或INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX
并比较COMPRESS_OPS
和COMPRESS_OPS_OK
来检查成功压缩操作与总压缩操作的比率。如果很大一部分压缩操作成功完成,则该表可能是压缩的理想选择。
如果您发现 压缩失败 的比例很高,您可以根据 第 17.9.1.6 节,“OLTP 工作负载的压缩” 中的说明调整
innodb_compression_level
、innodb_compression_failure_threshold_pct
和innodb_compression_pad_pct_max
选项,然后尝试进一步测试。
数据库压缩与应用程序压缩
决定是在应用程序中压缩数据还是在表中压缩数据;不要对同一数据使用两种类型的压缩。当您在应用程序中压缩数据并将结果存储在压缩表中时,额外的空间节省非常不可能,双重压缩只会浪费 CPU 周期。
在数据库中压缩
启用后,MySQL 表压缩是自动的,并应用于所有列和索引值。仍然可以使用 LIKE
等运算符测试列,即使索引值被压缩,排序操作仍然可以使用索引。由于索引通常占数据库总大小的很大一部分,因此压缩可以显着节省存储、I/O 或处理器时间。压缩和解压缩操作发生在数据库服务器上,该服务器可能是一个功能强大的系统,其规模足以处理预期的负载。
在应用程序中压缩
如果在将数据(例如文本)插入数据库之前,您在应用程序中压缩了数据,则可以通过压缩某些列而不压缩其他列来节省对不能很好地压缩的数据的开销。这种方法使用客户端机器而不是数据库服务器上的 CPU 周期进行压缩和解压缩,这可能适用于具有多个客户端的分布式应用程序,或者客户端机器有空闲 CPU 周期的情况。
混合方法
当然,可以组合这些方法。对于某些应用程序,使用一些压缩表和一些未压缩表可能是合适的。最好将某些数据进行外部压缩(并将其存储在未压缩的表中),并允许 MySQL 压缩应用程序中的其他表(其中一些)。与往常一样,前期设计和现实生活测试对于做出正确决策至关重要。
工作负载特性和压缩
除了选择要压缩的表(以及页面大小)之外,工作负载是影响性能的另一个关键因素。如果应用程序主要以读取为主,而不是以更新为主,那么在索引页面没有足够空间容纳 MySQL 为压缩数据维护的每页 “修改日志” 之后,需要重新组织和重新压缩的页面更少。如果更新主要更改非索引列或包含 BLOB
或存储在 “页面外” 的大型字符串的列,则压缩的开销可能是可以接受的。如果对表的唯一更改是使用单调递增的主键进行的 INSERT
操作,并且辅助索引很少,则几乎不需要重新组织和重新压缩索引页面。由于 MySQL 可以通过修改未压缩的数据来 “删除标记” 和 “就地” 删除压缩页面上的行,因此对表的 DELETE
操作效率相对较高。
对于某些环境,加载数据所需的时间与运行时检索一样重要。特别是在数据仓库环境中,许多表可能是只读或主要读取的。在这些情况下,可能或可能不接受以增加加载时间为代价来支付压缩的成本,除非由此带来的减少磁盘读取量或存储成本的节省是巨大的。
从根本上说,当有可用于压缩和解压缩数据的 CPU 时间时,压缩效果最佳。因此,如果您的工作负载是 I/O 密集型的,而不是 CPU 密集型的,您可能会发现压缩可以提高整体性能。当您使用不同的压缩配置测试应用程序性能时,请在类似于生产系统计划配置的平台上进行测试。
配置特性和压缩
从磁盘读取和写入数据库 页面 是系统性能中最慢的方面。压缩试图通过使用 CPU 时间压缩和解压缩数据来减少 I/O,并且当 I/O 成为与处理器周期相比的相对稀缺资源时,压缩最有效。
这在使用快速、多核 CPU 的多用户环境中通常尤其如此。当压缩表的页面在内存中时,MySQL 通常在 缓冲池 中使用额外的内存(通常为 16KB)来保存页面的未压缩副本。自适应 LRU 算法试图平衡压缩页面和未压缩页面之间的内存使用,以考虑工作负载是在 I/O 密集型方式还是 CPU 密集型方式运行。尽管如此,在使用压缩表时,分配给缓冲池更多内存的配置往往比内存高度受限的配置运行得更好。
选择压缩页面大小
压缩页面大小的最佳设置取决于表及其索引包含的数据类型和分布。压缩页面大小始终应该大于最大记录大小,否则操作可能会失败,如 B 树页面的压缩 中所述。
将压缩页面大小设置得过大,会浪费一些空间,但页面不需要频繁压缩。如果压缩页面大小设置得太小,则插入或更新可能会需要进行耗时的重新压缩,并且 B 树 节点可能需要更频繁地拆分,从而导致更大的数据文件和效率较低的索引。
通常,将压缩页面大小设置为 8K 或 4K 字节。鉴于 InnoDB 表的最大行大小约为 8K,KEY_BLOCK_SIZE=8
通常是一个安全的选择。