MySQL道普請便り

第165回MySQLの圧縮いろいろ

MySQLを運用していると、さまざまなファイルやテーブルが予想していたよりも大きくなり、ストレージ容量を逼迫する問題が起こることがあります。また、クエリの結果セットが大きいためにネットワーク帯域が逼迫され、問題になることもあると思います。これらの問題はスケールアップ、データベースシャーディング、または圧縮機能などを使って解決できます。

今回はその中から、MySQLが提供しているさまざまな圧縮機能についてまとめて紹介します。MySQLではデータ、テーブル、バイナリログやデータ転送に圧縮機能を提供しています。

関数によるデータ圧縮

はじめに、関数によるデータを圧縮する方法を紹介します。

データ圧縮を行うのはCOMPRESS関数です。指定した文字列をzlibで圧縮して、その結果をバイナリ文字列として返します。展開するにはUNCOMPRESS関数を使用します。

文字コードの変換など発生を防ぐために、格納するテーブルのカラムタイプはblog型などのバイナリ型が推奨されています。この関数を使って、特定のカラムのデータサイズを圧縮することができます。

mysql> CREATE TABLE compress (col1 blob);
Query OK, 0 rows affected (0.02 sec)

mysql> INSERT INTO compress(col1) values (COMPRESS(REPEAT('C',10)));
Query OK, 1 row affected (0.00 sec)

mysql> SELECT UNCOMPRESS(col1) FROM compress;
+------------------+
| UNCOMPRESS(col1) |
+------------------+
| CCCCCCCCCC       |
+------------------+
1 row in set (0.00 sec)

(mysqlコマンドに--skip-binary-as-hexオプションを設定して実行しています)

詳しくは、マニュアルの12.14 暗号化関数と圧縮関数をご参照ください。

テーブル圧縮

InnoDBでは2種類の圧縮機能を提供しています。

圧縮テーブル

設定されたinnodb_page_size値よりも小さいページサイズでテーブルを構成します。そのためテーブルのサイズが小さくなり、I/Oが削減、スループットが改善されますが、CPU使用率が上昇しパフォーマンスに影響する可能性があります。

CREATE TABLEステートメントにROW_FORMAT=COMPRESSED句を使用してテーブルを作成します。file-per-tableと一般テーブルスペースに適用可能です。

mysql> CREATE TABLE comp1 (col1 int) ROW_FORMAT=COMPRESSED;

詳しくは、15.9.1 InnoDBテーブルの圧縮をご参照ください。

透過的ページ圧縮

指定された圧縮アルゴリズムを利用してページを圧縮し、ホールパンチングメカニズムによってページの最後から空のブロックが解放されることで、テーブルのサイズが小さくなります。CREATE TABLEステートメントにCOMPRESSION属性を使用してテーブルを作成します。COMPRESSION属性にはzlibまたはlz4の指定ができます。

MySQL 5.7から登場した機能で、file-per-tableのみに適用可能です。

mysql> CREATE TABLE comp2 (col1 int) COMPRESSION='zlib';

OSのスパースファイルなどの機能を使って圧縮するため、サポートされるプラットフォームの制限があります。詳しくは、15.9.2 InnoDBページ圧縮をご参照ください。

圧縮テーブルと透過的ページ圧縮を比べると、透過的ページ圧縮はパフォーマンスへの影響は小さいといえます。ただし、バックアップにxtrabackupを使って運用をしていると、圧縮展開後のサイズでリストアされてしまい、稼働していたMySQLと同一スペックのサーバーではディスク領域が不足するためリストアできない問題があります。導入する際は、しっかり運用テストを行ったほうが良いでしょう。

バイナリログ圧縮

続いて、MySQL8.0.20から導入されたバイナリログの圧縮です。binlog_transaction_compressionシステム変数をONにすることで、圧縮が有効化されます。デフォルトはOFFです。

mysql> SET GLOBAL binlog_transaction_compression=ON;
Query OK, 0 rows affected (0.00 sec)

binlog_transaction_compression_level_zstdシステム変数を使用して、圧縮に使用されるzstdアルゴリズムのレベルを設定します。レプリカは圧縮状態のままリレーログに書き込まれるため、レプリカでもディスク領域を節約できます。

また、パフォーマンススキーマのbinary_log_transaction_compression_statsテーブルから統計の確認ができます。

詳しくは、5.4.4.5 バイナリログトランザクション圧縮をご参照ください。

トラフィック圧縮

クライアントとサーバー間のトラフィックを圧縮し、接続を介して送信されるバイト数を減らすことができます。

MySQL 8.0.17とそれ以前(レガシー接続圧縮)

MySQL 8.0.17とそれ以前では、レガシー接続圧縮を提供しています。

  • クライアントプログラムの--compressコマンドラインオプション
  • MySQL C APIのmysql_options()関数のMYSQL_OPT_COMPRESSオプション
  • レプリケーションのslave_compressed_protocolシステム変数

レガシー接続圧縮はMySQL 8.0.18以降は非推奨であり、将来のバージョンでは削除される予定です。

MySQL 8.0.18とそれ以降protocol_compression_algorithms

MySQL 8.0.18とそれ以降では、protocol_compression_algorithmsシステム変数にて制御するようになっています。変数には許可する圧縮アルゴリズムをカンマ区切りで指定できるようになっており、デフォルトはzlib,zstd,uncompressedとなっています。つまり、現在使用できるすべてのアルゴリズムが許可されています。

このシステム変数はクライアントとサーバ間、とレプリケーションまたはグループレプリケーションに参加しているサーバーによる接続も含まれます。

接続を正常に設定するには、接続の両側が相互に許可された圧縮アルゴリズムに同意する必要があります。

mysqlコマンドラインクライアントからzlibでアクセスする例
$  mysql --compression-algorithms=zlib

mysql> show status like 'Compression_algorithm';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| Compression_algorithm | zlib  |
+-----------------------+-------+

Compression_algorithmステータス変数からどの圧縮アルゴリズムで接続しているかわかります。

zlib接続でレプリケーションを設定する例
CHANGE REPLICATION SOURCE TO
  SOURCE_COMPRESSION_ALGORITHMS = 'zlib'
  ....

トラフィック圧縮についての詳細は、4.2.8 接続圧縮制御をご参照ください。

まとめ

今回はMySQLが提供している圧縮機能をまとめて紹介しました。圧縮機能は圧縮していないよりもCPUを多く使うなどパフォーマンスに影響があります。パフォーマンスを最優先にするなら圧縮は無効にしたほうがいいでしょう。それぞれ概要だけの説明ではありましたが、気になる機能があれば深堀りしてみてはいかがでしょうか。

おすすめ記事

記事・ニュース一覧