fetchrow時の使用メモリ
topコマンドで調べてもよく分からんので、http://www.drk7.jp/MT/archives/000803.htmlを参考にDevel::Size::Reportを使って調べてみる。
上記サイトによれば
SCALAR 型のデータは、Integer 型である場合、最小で16byte のメモリを必要とする。以後、32bit 単位で 4byte 増加する。String 型の場合、最小で25 byte のメモリを必要とし、以後 1 ASCII につき 1byte 必要とする。
とのこと。実際に自分で試してみてもこんな感じだった。
さて、実験。
テーブルスキーマはこんな感じ。
mysql> show create table data \G *************************** 1. row *************************** Table: data Create Table: CREATE TABLE `data` ( `id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned NOT NULL, `post_date` int(10) unsigned NOT NULL, `content` varchar(100) NOT NULL, PRIMARY KEY (`id`), KEY `i1` (`user_id`,`post_date`), KEY `i2` (`post_date`) ) ENGINE=InnoDB DEFAULT CHARSET=cp932
調べるために10行をfetchrow_hashrefしてみる。
use Devel::Size::Report qw/report_size/; my $LIMIT = 10; my $dbh = getHandle(); my $sth = $dbh->prepare(<<"SQL"); select * from data limit $LIMIT; SQL $sth->execute(); my @list = (); while (my $hash = $sth->fetchrow_hashref) { push (@list, $hash); } print report_size(\@list, { indent => ' '});
調べてみると以下のことが分かった。
- id, post_date, user_idに関して
- int(10)だが文字列として扱われている
- 30byte = 25bytes + 5ascii(=5bytes)
- 5asciiなのはSeqが10000〜にしているため(5桁)
- contentはvarcharなのでメモリサイズも可変
- Hash refのoverheadがメチャクチャデカイ(=ほぼ2/3)
- Array refのoverheadはHash refに比べて小さいのでほぼ無視できるはず
ものすごく単純化すると、
①selectされるcolumnの合計byte数 × ②レコード数 × 3倍(hash refのoverhead)
という計算式が成り立ちそうである。
試しに10万行をSELECTしたとして、計算してみる。
`id` int(10) unsigned NOT NULL, `user_id` int(10) unsigned NOT NULL, `post_date` int(10) unsigned NOT NULL, `content` varchar(100) NOT NULL,
どんなデータが入っているか分からないので、それぞれaverageと仮定する。
①は (25+5)+(25+5)+(25+5)+(25+50) = 165 bytes
となるので、
165byte × 10万行 × 3 = 48339 Kbytes = 47Mbytes
と予測が立つ。実際、プログラムを実行して確認すると、
35461 Kbytes = 34 Mbytes
でオーダーとしては正しかった。
数10Mbytesレベルなら、今日のサーバならなんなく捌けるはずなので問題はないはず。
ただ、コピーしまくるとなかなか大変そうなので、リファレンスをうまく使う必要はありそうだ。
ちなみに、詳細結果は以下の通り。
Size report v0.13 for 'ARRAY(0x936bb60)': Array ref 3677 bytes (overhead: 120 bytes, 3.26%) Hash ref 370 bytes (overhead: 229 bytes, 61.89%) 'id' => Scalar 30 bytes 'content' => Scalar 46 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 355 bytes (overhead: 229 bytes, 64.51%) 'id' => Scalar 30 bytes 'content' => Scalar 31 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Hash ref 354 bytes (overhead: 229 bytes, 64.69%) 'id' => Scalar 30 bytes 'content' => Scalar 30 bytes 'post_date' => Scalar 35 bytes 'user_id' => Scalar 30 bytes Total: 3677 bytes in 51 elements