とある案件で、投稿数が10万を軽く超え、カスタムフィールドテーブルの合計が1000万レコードに届くシステムを作ることになりました。
WordPressが適切かという意見はありそうですが、サイトなので、WordPressの強力な管理画面とプラグインを利用したかったわけです。
しかし、meta_queryが遅い!、1つのメタキーに条件をセットするだけで返ってくるのに1分かかります。これではサイトとして問題があるわけです。なぜ、遅いかというと、WordPressはカスタムフィールドの情報を1つのテーブルに縦に持っています(この表現で伝わってほしい!)
そこで、カスタムフィールドの情報を1post=1レコードのテーブルに展開してmeta_queryを高速化するプラグインを作ってみました。
使い方は簡単「meta accelerator」をいうプラグインを公式ディレクトリからインストール
https://wordpress.org/plugins/meta-accelerator/
有効化すると、メニューに「meta speedup」という項目が増えます。これを開くと、
こんな感じに、投稿タイプが縦に並んだ画面が表示されます。そこで、高速化したい投稿タイプの横の「create accelerator」をクリック(レコード数が多い場合はかなり待たされます。)、処理が終わると、下のようにボタンが変わります。
この状態で、高速化完了、上のボタンは「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でしか検証していません。
※後、あくまで自己責任でよろしくお願いします!