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