MySQLに大型のデータを圧縮したい
経緯
同じリクエストに対して同じレスポンスを数日程度返せるようにしたい
redisに保存していたがメモリ逼迫しはじめたのでMySQLに逃がすこととする
この時、DB容量ケアの為レスポンスは圧縮データとしたい
テーブルの作成
対象カラムはlongblob型とした
CREATE TABLE IF NOT EXISTS `user_data_t` (
`user_data_id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` int(11) unsigned NOT NULL COMMENT 'ユーザーID',
`bin_data` longblob,
`create_time` datetime NOT NULL COMMENT '作成日時',
`update_time` datetime NOT NULL COMMENT '更新日時',
`delete_flg` tinyint(4) unsigned NOT NULL DEFAULT '0' COMMENT '削除フラグ',
PRIMARY KEY (`user_data_id`),
UNIQUE KEY `user_id` (`user_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='テスト' AUTO_INCREMENT=1;
検証
非圧縮
$sampleData = array(
'hoge' => array(1,2,3),
'huga' => array(3,4,5),
'hego' => 11213,
'huga1' => array(3,4,5),
'huga2' => array(3,4,5),
'huga3' => array(3,4,5),
'huga4' => array(3,4,5),
'huga5' => array(3,4,5),
'huga6' => array(3,4,5),
'huga7' => array(3,4,5),
'huga8' => array(3,4,5),
'huga9' => array(3,4,5),
'hugaA' => array(3,4,5),
'hugaB' => array(3,4,5),
'hugaC' => array(3,4,5),
'hugaD' => array(3,4,5),
'hugaE' => array(3,4,5),
'hugaF' => array(3,4,5),
'hugaG' => array(3,4,5),
'hugaH' => array(3,4,5),
);
$insertData = [
'user_id' => $userId,
'resume_type' => $resumeType,
'bin_data' => json_encode($targetData),
];
$insertKey = $this->insert($insertData);
サイズ確認
mysql [xxxx] select octet_length(bin_data) from user_data_t WHERE user_data_id = 1;
--------------
select octet_length(bin_data) from user_data_t WHERE user_data_id = 1
--------------
+------------------------+
| octet_length(bin_data) |
+------------------------+
| 316 |
+------------------------+
1 row in set (0.00 sec)
圧縮
gzcompress
文字列を圧縮する標準メソッド(gzip圧縮とは違うらしい)
https://www.php.net/manual/ja/function.gzcompress.php
$sampleData = array(
'hoge' => array(1,2,3),
'huga' => array(3,4,5),
'hego' => 11213,
'huga1' => array(3,4,5),
'huga2' => array(3,4,5),
'huga3' => array(3,4,5),
'huga4' => array(3,4,5),
'huga5' => array(3,4,5),
'huga6' => array(3,4,5),
'huga7' => array(3,4,5),
'huga8' => array(3,4,5),
'huga9' => array(3,4,5),
'hugaA' => array(3,4,5),
'hugaB' => array(3,4,5),
'hugaC' => array(3,4,5),
'hugaD' => array(3,4,5),
'hugaE' => array(3,4,5),
'hugaF' => array(3,4,5),
'hugaG' => array(3,4,5),
'hugaH' => array(3,4,5),
);
$insertData = [
'user_id' => $userId,
'resume_type' => $resumeType,
'bin_data' => gzcompress(json_encode($reportData)),
];
$insertKey = $this->insert($insertData);
サイズ確認
mysql [xxx] select octet_length(bin_data) from user_data_t WHERE user_data_id = 2;
--------------
select octet_length(bin_data) from user_data_t WHERE user_data_id = 2
--------------
+------------------------+
| octet_length(bin_data) |
+------------------------+
| 95 |
+------------------------+
1 row in set (0.00 sec)
圧縮結果
実際のarrayデータから1/3のサイズで保存できた
スピード
上記insertを100回で計測
非圧縮
float(3.0973808765411)
float(3.1544151306152)
float(3.0928800106049)
float(3.3873400688171)
float(3.2760629653931)
圧縮
float(3.1296010017395)
float(3.3456451892853)
float(3.3879458904266)
float(3.1482610702515)
float(3.1463890075684)
結論
10%ほど遅くなるか。inpuptするデータサイズにもよりそう?