CreateField Blog

オープンソースを使って個人でWebサービスを開発・運営していたブログ

MySQLでカラムごとに圧縮する方法

MySQLでデータサイズが非常に大きいような場合、データを圧縮して格納したくなることがあります。

InnoDBではROW_FORMAT=compressedとすることで、テーブルを圧縮することができます。 MyISAMではmyisampackコマンドを利用することにより、テーブル全体を圧縮することができます。ただし、MyISAMでは読み取り専用となります。

通常、主キーやタイトル、メタデータなどのサイズは小さく、bodyなどのサイズが大きいことが多いと思います。そのため、テーブル全体ではなく、特定のカラムのみを圧縮するだけで事足りることが大半だと思います。

MySQLではCOMPRESS関数とUNCOMPRESS関数があります。

MySQL :: MySQL 5.6 Reference Manual :: 12.13 Encryption and Compression Functions

そこで、これとBLOB型のカラムを利用することによりカラム単位で圧縮することができます。

COMPRESS関数ではZLIB圧縮されるため、30%〜50%ぐらいになります。ただし、その分、伸長にかかるCPU負荷が増えるはずです*1

CREATE TABLE `comp` (
  `body` longblob NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

INSERT comp VALUES(COMPRESS("hoge hoge hoge hoge hoge hoge"));

SELECT UNCOMPRESS(body) FROM comp;
+-------------------------------+
| UNCOMPRESS(body)              |
+-------------------------------+
| hoge hoge hoge hoge hoge hoge |
+-------------------------------+
1 row in set (0.00 sec)

これで、アプリ側でCOMPRESSとUNCOMPRESSつけるのが若干めんどいですがカラム単位で圧縮することができます。

理想的にはアプリを改修することなく、圧縮・解凍できるようにMySQL側で自動でCOMPRESSとUNCOMPRESSができるようにしたいですね。

実現方法はQuery Rewrite Pluginぐらいしかないのかしら。なんかいい方法ないかなぁ。

追記

generated columnを使えば自動的にUNCOMPRESSはできるみたい。

MySQLでgenerated columnを使って圧縮したデータを自動的に解凍する - CreateField Blog

*1:具体的な負荷は検証してません。ところで、マニュアルではsuch as zlibっていってますが、他の圧縮ライブラリが使えるように実装されているんですかね?LZ4やsnappyなどの伸長速度優先のアルゴリズムが利用できれば、高速に伸長できて良さそうです。そのうち調べるかも、調べないかも