「ひとつのキーに、まとめてデータを入れるとオーバーヘッドがかかるかもしれないよ」
と教えられ、現在ひとつのキーに入れないような設計をしている最中で、
じゃあ、試しに、1,000の値 を、
- ひとつのキーに全データをシリアライズして入れる
- 1,000のキーとして入れる
というそれぞれの方法では、実際にどれだけオーバーヘッドの可能性があるかどうか。
ターゲットは wp_options
オーバーヘッドは一切ありません。

ここで挿入する値の定義
1,000個の1~10,000,000の乱数を作成して挿入
つまり、
array( 0 => 2384、093, 1 => 6923230, 2 => 8053892, ... 999 => 1034544 );
のようなデータです。
データには日本語や英文が入る場合が多いので、今回はデータ量が少ない気がして、
良いテストかどうかと聞かれれば、分かりません。としか答えられませんが、
少しぐらいは何か分かるのではないかと思い、やってみることにしました。
wp_options にまずは、ひとつのキーに1,000の配列を挿入することを仮定して、試してみました。
$SampleData = array(); for( $i=0; $i<1000; $i++ ) { $SampleData[$i] = rand( 1 , 1000000 ); } print_r($SampleData);
print_r で値を確認。1,000の配列が出来ています。
これを、wp_optionsへひとつのキーとして、シリアライズしたデータをupdate_optionで挿入してみると、

ぎっしりはいりました。結果…
オーバーヘッドはなし。
えっ? これじゃ検証にならない。。もっとデータ量を増やして試してみよう。
ということで、オーバーヘッドされるまで、データ量を増やしながら色々と試行錯誤…。
結果。どんなに頑張ってもオーバーヘッドしなかった。。
参ったなぁ。指摘されているから、オーバーヘッドするはずなんだけど…
実際にオーバーヘッドしているテーブルがあったので、そのテーブルとひたすらにらめっこ。
すると、気づきました…。

MyISAM
ん?「MyISAM」?私のイサム?メルティーラブ??
軽めにググってみました。
あ、データベースにも色々とデータの種類があるのね。全く知りませんでした。
で、さっそくテスト環境に使っているテーブルの型を、MyISAMに変更。
同じように1,000個の値を持つ乱数配列で再度update_optionでデータを挿入すると…
でました。オーバーヘッド。

ひとつのキーに、1,000個の、乱数で作成された値をもつ配列を、シリアライズして挿入すると、
29.5 KiB (KiBって何?キロバイトじゃなくて?)
計10回、挿入してみましたが、 29.5 KiBから変わらなかったです。
なるほど。何度も値を挿入しても、値は変わらないのか。配列の値も色々と変えてみる。
ここまでで分かったこと
× 1回のオーバーヘッド量 29.5 KiB × 10回updateすると = 295KiB になるわけではなく、
○ 挿入するデータ量に応じて、オーバーヘッドのサイズが変わる。何度更新しても。
そっか。
これじゃあ何度テーブルの最適化をしても、そのupdateをする限りいつまでもオーバーヘッドするじゃないか。
よし。
次の検証にうつります。その前に、オーバーヘッドの最適化。
次は、1,000のキーとして、値を挿入。の検証
挿入するデータは以下。
for( $i=0; $i<1000; $i++ ) {
update_option( 'sampledata' . $i , rand( 1 , 1000000 ) );
}
結果は。オーバーヘッドなし
確かにこの方法がいいかもしれない。
ん?ちょっとここでもうひとつ試してみることにしました。
update_optionの値を、ただの配列にするとどうなるか
for( $i=0; $i<1000; $i++ ) { update_option( 'sampledata' . $i , array( rand( 1 , 1000000 ) ) ); }
結果はこちら。

20 バイト。配列にするだけで、オーバーヘッドが起こるのか。
wordpress の update_option()の流れとしては(ざっくり)、
- update_option() の値に配列やオブジェクトをつっこむ
- maybe_serialize()という処理が入る
この”たぶん、シリアライズ機能”のほうで、
if ( is_array( $data ) || is_object( $data ) ) return serialize( $data );
シリアライズされたデータを返し、データベースのデータが更新されます。
じゃあ、配列でupdate_optionデータを更新する限り、シリアライズされる。
シリアライズされたデータで、 データベースの型が MyISAM なら、ほぼオーバーヘッドが起こる。
(データベースの環境も左右されるかもしれませんね)
いい勉強になりました。
オーバーヘッドを避ける為には、1キーに1つの値。
という事ですね。
今公開中のプラグインは、ほとんどがシリアライズされたデータなので、いくつかは変更する予定です。
>>追記
実際には、1キー に 1つの値 にしても、オーバーヘッドを避ける事はできませんでした。
どういう事かというと…
作成したキーを、削除するだけでもオーバーヘッドが出ました。
また、コメントでbloger323さんがおっしゃる通り、データの増減が激しい場合もオーバーヘッドが出るようです。
うーん、どういう構造がいいんでしょうね。。
あのコメントは実行速度のことを言っている様に思います。
1キー 1値ならば取り出してお終いですが、複数値をまとめて格納した場合、取り出した後に分解する処理が必要となるので、その部分を指してオーバーヘッドと言っているのだと思うのです。
何故そう考えるかというと、この記事で触れているデータベースのオーバーヘッドは 1キー 1値にしても解消しないからです。
可変長のフィールドを持つテーブル (wp_options もそうですね) で、例えば大きいデータから小さいデータに更新するようなケースでは 1キー 1値でもオーバーヘッドが生じるはずです。
そこはもうプラグインの処理ではなく OPTIMIZE TABLE を実行しましょう、という話でいいと思うし、気にするのも MB の単位になってからでいいように思います。
1キー 1値にすることを検討されているようですが、コメントをくれた人も実際に計測して言っているわけではないと思うので気にし過ぎる必要はないと思います。
格納方法を変えようとすると互換性を取るのも大変ですし。
きちんと手を動かして試すのは素晴らしいですね。
blogger323さん
コメントありがとうございます。
確かに、実行速度の事かもしれませんね。
今の格納方法だと、たったひとつの値を取り出すにしても、全てのデータを分解して、ソートをかけて、ソートされたデータから、ひとつずつ取り出す方式なので。
blogger323さんのおっしゃる通り、 “最適化すればいいんじゃん?” と考えたのですが、
今回指摘されたプラグインだけが、ユーザーがいくらでも値を作成することのできるプラグインで、
データ量が増えれば増えるほどに処理量が確実に増えるので、
指摘されたのではと考えています。
(逆に言えば、プラグインの処理を見ている方もいるんだなと思いました。)
wp_optionsを用いて1キー 1値の方法をやろうとテストしてみましたが、とても扱いづらく、結局処理も多くかかったので、格納方法に関してはすぐには対応は難しいですが、 wp_プラグイン名 等でテーブルを使う方法を検討中です。
色々と教えていただき、ありがとうございます。