Custom Options Plus Post In バージョンアップ

このたび、CUSTOM OPTIONS PLUS POST IN のバージョンアップをおこないました。

最新バージョンは、1.2となります。
主にデータベース周りの格納方法の更新を行いました。

 

一度シリアライズしたデータを格納、取り出す際はシリアライズし、
ひとつのデータを取り出す形式について、おそらく処理を指摘されていたので変更しました。

 

今まで

wp_options 内に、キー coppi として格納

coppi1.2以前の格納方法
coppi1.2以前の格納方法

 

現在

テーブルを用意した格納方法

 

coppiテーブル
coppiテーブル
データ格納サンプル
データ格納サンプル

update_option 及び get_optionを使わずに、テーブルを用意するので、そもそも、

どうやってやるんだろう。。と色々思考錯誤しましたが、下記の記事に感謝です。

 

Creating_Tables_with_Plugins

http://codex.wordpress.org/Creating_Tables_with_Plugins

■ WordPressでデータベースを使ったプラグインを作成する

http://takahashifumiki.com/web/programing/1440/

 

テーブルを用意することでのメリットは、まずは ソート がかなり楽になりました。
今まではget_option全データをとにかく取得し、指定されたソートの順序になるようarray_multisortを行っていたのですが、sqlクエリとして投げるだけなので、返ってきたデータがソート済み。

次に、一つのデータを取り出すのも楽になりました。

 

プラグインが有効化された際に、テーブルを作成し、元のデータを取得しそこに複製された時は、
おぉーってなりましたねw

 

ただ、sqlクエリを直接書くことになるので、脆弱性が気になります。
(sqlに限った事じゃないですが)

試していて、よく分からなかった 「$wpdb->prepare」。

wordpress 3.4.2 のバージョンでテスト動作を繰り替えし、動作確認をして、
いざ wordpress 3.5 で動作をすると、

Warning: Missing argument 2 for wpdb::prepare()

が連発。んん??どういうエラーなんだろうと色々とぐぐってみました。

$wpdb->prepare() 自体の動作は、SQL インジェクション攻撃からクエリを保護する によると、
クエリを保護するためにエスケープするためのもの。らしいのですが、こんな記事もありました。

Warning: Missing argument 2 for wpdb::prepare()は危険!

正しい使い方をしないと、危ないよ。という事らしいです。

3.4ではエラーも出ないのか。。そもそも使い方を間違っていたと。

この記事の下のほうまで読んでいくと、akismetプラグインの場合の記述リンクがあったので見てみると、

 $remaining = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM $wpdb->commentmeta WHERE meta_key = 'akismet_error'" ) );

$remaining = $wpdb->get_var( "SELECT COUNT(*) FROM $wpdb->commentmeta WHERE meta_key = 'akismet_error'" );

こうなっていました。

$wpdb->prepare を外したんですね。

今回はakismetプラグインを参考にして、$wpdb->prepare を外すと動作OK。3.4.2で試しもてもOK。

とりあえず、今回はこれでよしとして、アップデートしました。

 

こういう面を色々と考えると、難しいです。
出来る限り、使えるテーブルは使ったほうが、ありがたい。のかも。

 

ダウンロードはこちら http://wordpress.org/extend/plugins/custom-options-plus-post-in/

データベースへのオーバーヘッドを試してみた

ひとつのキーに、まとめてデータを入れるとオーバーヘッドがかかるかもしれないよ」

と教えられ、現在ひとつのキーに入れないような設計をしている最中で、

 

じゃあ、試しに、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さんがおっしゃる通り、データの増減が激しい場合もオーバーヘッドが出るようです。

 

うーん、どういう構造がいいんでしょうね。。