通常,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 实例,并针对 Information Schema
INNODB_CMP
表格运行查询。对于涉及多个压缩表格的工作负载的更复杂的测试,请针对 Information Schema
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
通常是一个安全的选择。