とある案件で、投稿数が10万を軽く超え、カスタムフィールドテーブルの合計が1000万レコードに届くシステムを作ることになりました。

WordPressが適切かという意見はありそうですが、サイトなので、WordPressの強力な管理画面とプラグインを利用したかったわけです。

しかし、meta_queryが遅い!、1つのメタキーに条件をセットするだけで返ってくるのに1分かかります。これではサイトとして問題があるわけです。なぜ、遅いかというと、WordPressはカスタムフィールドの情報を1つのテーブルに縦に持っています(この表現で伝わってほしい!)

そこで、カスタムフィールドの情報を1post=1レコードのテーブルに展開してmeta_queryを高速化するプラグインを作ってみました。

使い方は簡単「meta accelerator」をいうプラグインを公式ディレクトリからインストール

https://wordpress.org/plugins/meta-accelerator/

meta_1

 

有効化すると、メニューに「meta speedup」という項目が増えます。これを開くと、

meta_2

こんな感じに、投稿タイプが縦に並んだ画面が表示されます。そこで、高速化したい投稿タイプの横の「create accelerator」をクリック(レコード数が多い場合はかなり待たされます。)、処理が終わると、下のようにボタンが変わります。

meta_3

この状態で、高速化完了、上のボタンは「delete accelerator」が高速化対象から削除、「recreate accelerator」が高速化のためのテーブルを再作成してくれます。

やっていることは単純で

  • 対象の投稿タイプの投稿を全検索して、カスタムフィールドを全て抽出、1投稿、1レコードの専用のテーブルを別に作成します。
  • 上で作成したテーブルに対象の投稿タイプの投稿からカスタムフィールドを取り出して、insertします。
  • 以後、カスタムフィールドを追加編集削除したり、投稿を追加した際に、上のテーブルを追加更新してゆきます。
  • meta_query実行時にデフォルトのwp_postmetaテーブルではなく上のテーブルを利用するようにSQLを書き換えます。

これで、1分かかっていた処理が1秒に短縮されました!

注意点がいくつか有ります。

  • 「create accelerator」中に投稿を追加したりカスタムフィールドが編集されると、その変更は反映されない場合があります。処理中は投稿や更新を行わないで下さい。
  • 複数のpost_typeを対象にしたWP_Queryには対応していません。複数のpost_typeを選択した時点で、通常のmeta_queryになります。
  • カスタムフィールドの値が配列(同じキーに複数の値がある)は、カンマ区切りでフィールドに格納して処理されます。(完全な対応とはいえない感じです)
  • 生成したテーブルにインデックスは貼っていません。(将来は貼れるようにすることも考えていますが、横に展開すればレコード数はかなり減るはずなので必要なケースは少ないと思います)
  • WordPress3.9.1でしか検証していません。

※後、あくまで自己責任でよろしくお願いします!