web-dev-qa-db-ja.com

HTML文字列、またはオブジェクトを格納するためにTransient APIを使用する必要がありますか?

非常に複雑なクエリで20の関連する投稿(各投稿に対して)を表示するプラグインがあるとしましょう。そして、このクエリからのデータを使用して、複雑なHTMLレイアウトを構築します。また、このプラグインは公開されており、どのような構成のどのサーバーにもインストールできることに注意してください。

何かのようなもの:

/* complex and large query */
$related_posts = get_posts( ... );

$html_output = '';
foreach($related_posts as $key => $item) {
     /* complex layout rendering logic (but not as slow as the previous query) */   
     $html_output .= ...;
}

だから私の質問は次のとおりです。

  • そのようなデータをキャッシュする最も安全で正しい方法は何ですか?
  • Transient APIを使用して$related_posts配列または$html_output文字列をキャッシュする必要がありますか? $html_ouput文字列をキャッシュする場合、最大サイズの制限に達するでしょうか?保存する前に、gzipする必要がありますか。
  • ここではTransient APIを使用する必要がありますか?
18
Marvin3

ここではTransient APIを使用する必要がありますか?

いいえ.

在庫WordPressのインストール時に一時的なものはwp_optionsテーブルに格納され、コアのアップグレード中にのみクリーンアップされます。 50,000件の投稿があるとします。これは、オプションテーブルに50,000行追加されているとします。明らかにそれらはautoload = noに設定されています、それでそれはあなたの記憶をすべて消費するつもりはありません、しかしもう一つの警告があります。

Optionsテーブルのautoloadフィールドにはインデックスがありません。これは、wp_load_alloptions()への呼び出しがフルテーブルスキャンを実行することを意味します。行数が多いほど、時間がかかります。頻繁にオプションテーブルに書き込むと、MySQLの内部キャッシュの効率が低下します。

キャッシュされたデータが投稿に直接関連している場合は、投稿メタに保存するほうが賢明です。ポストメタキャッシュは(通常)WP_Queryでのポスト検索中にプライミングされるため、キャッシュされたコンテンツを表示する必要があるたびにクエリを節約することもできます。

メタ値のデータ構造はさまざまであり、キャッシュされた値が古くなっている場合は一時的な動作のように、タイムスタンプを取得して高価なクエリを実行できます。

留意すべきもう1つの重要な点は、WordPressのトランジェントは永続的なオブジェクトキャッシングがある環境では不安定になる可能性があるということです。つまり、キャッシュされたデータを一時的に24時間保存したとしても、それが23時間、つまり12分、さらには5分以内に利用可能になるという保証はまったくありません。多くのインストールのためのオブジェクトキャッシュバックエンドはRedisやMemcachedのようなインメモリのKey-Valueストアで、新しいオブジェクトに適合するのに十分な割り当てられたメモリがなければ、古いアイテムは追い出されます。これはメタストレージアプローチにとって大きな勝利です。

無効化も賢くなります。つまり、X時間で関連する投稿キャッシュを無効にするのはなぜですか。内容が変わったからでしょうか。新しい投稿が追加されましたか?新しいタグが割り当てられましたか? 「複雑で大規模なクエリ」によっては、クエリの結果を変更するようなことが起こった場合にのみ無効にすることを選択できます。

Transient APIを使用して$ related_posts配列、または$ html_output文字列をキャッシュする必要がありますか? $ html_ouput文字列をキャッシュした場合、最大サイズの上限に達するでしょうか?保存する前に、gzipする必要がありますか。

それはあなたの文字列のサイズに大きく依存します。それはそれがPHP、MySQL、その他の間で流れるデータであるからです。MySQLの限界に達するために非常に努力する必要があります。わずか1 MB。

あなたの「複雑なレイアウトレンダリングロジック」は実際にどのくらいかかりますか?見つけるためにプロファイラーを通してそれを実行します。それは非常に速いので、ボトルネックになることは決してないでしょう。

その場合は、投稿IDをキャッシュすることをお勧めします。 WP_Postオブジェクトではありません。なぜなら、それらは完全な投稿内容を含むだけで、投稿IDの配列だけを含むからです。それからWP_Querypost__inを使用するだけで、主キーによるMySQLクエリが非常に高速になります。

つまり、項目ごとに必要なデータがかなり単純な場合(おそらくタイトル、サムネイルのURL、パーマリンク)、MySQLへの余分なラウンドトリップのオーバーヘッド、および非常に長いHTMLのキャッシュのオーバーヘッドなしで、これら3つだけを格納できます。文字列.

うわー、それは言葉がたくさんある、それが役立つことを願っています。

18
kovshenin

すべてのWPコードがパブリックコードではない

何かを公開する場合は、 kovshenin のすべてが完全に有効です。

あなた自身またはあなたの会社のためにプライベートコードを書くつもりなら、状況は異なります。

外部オブジェクトキャッシュは、どんな場合でも大きなメリットです

外部の永続オブジェクトキャッシュを設定するには、可能な場合はをお勧めします

トランジェントとMySQLに関するkovsheninの答えで述べられていることはすべて真実です。WP自体と多数のプラグインがオブジェクトキャッシュを利用することを考えると... )RedisやMemcachedのような最新のキャッシュシステムをセットアップする努力。

キャッシュされた値が存在しない可能性があります:それでいい

さらに、はい、外部オブジェクトキャッシュはnot信頼性があります。トランジェントがそこにあるという事実に決して頼るべきではありません。キャッシュがshouldであるはずの場所にない場合に動作することを確認する必要があります。

キャッシュはストレージではなく、キャッシュはキャッシュです。

キャッシュを選択的に使用する

この例を参照してください。

function my_get_some_value($key) {
   // by default no cache when debug and if no external object_cache
   $defUse = ! (defined('WP_DEBUG') && WP_DEBUG) && wp_using_ext_object_cache();
   // make the usage of cache filterable
   $useCache = apply_filters('my_use_cache', $defUse);
   // return cached value if any
   if ($useCache && ($cached = get_transient($key))) {
     return $cached;
   }
   // no cached value, make sure your code works with no cache
   $value = my_get_some_value_in_some_expensive_way();
   // set cache, if allowed
   $useCache and set_transient($key, $value, HOUR_IN_SECONDS);

   return $value;
}

このようなコードを使用して、プライベートサイトでは、特に多くのユーザーがいる場合、サイトのパフォーマンスをalot改善できます。

ご了承ください:

  • デフォルトでは、デバッグがオンの場合、キャッシュは使用されないため、開発環境で使用することをお勧めします。私を信じて、キャッシュはデバッグを地獄にすることができる
  • WPが外部オブジェクトキャッシュを使用するように設定されていない場合、デフォルトではキャッシュも使用されません。これは、MySQLを使用するときに一時的なものを使用しないため、MySQLに関連するすべての問題が存在しないことを意味します。おそらくもっと簡単な代替方法は wp_cache_* functions を使用することです。したがって、外部キャッシュがセットアップされていない場合、キャッシュはメモリ内で発生し、データベースは一切関与しません。
  • キャッシュの使用はフィルター処理可能で、発生する可能性のあるEdgeのケースを処理します

キャッシュがなければWebscaleはありません

キャッシュの速度の問題を解決しようとしないでください。速度に問題がある場合は、コードを再考する必要があります。

しかし、webscaleでWebサイトをスケーリングするには、キャッシュはかなり必要です

また、多くの場合(常にではありませんが)断片化されたコンテキスト対応キャッシュは、積極的なフルページキャッシュよりもはるかに柔軟で適切です。

あなたの質問:

ここでTransient APIを使用する必要がありますか?

依存します

あなたのコードは多くのリソースを消費していますか?そうでない場合、キャッシュの必要はないかもしれません。前述のように、スピードだけではありません。コードは高速ですが、2人のユーザーに大量のCPUとメモリが必要な場合... 100人または1000人の同時ユーザーがいる場合はどうなりますか?

キャッシュを実現することをお勧めします。

...そして公開コード:おそらくno。上記の公開コードの例のように、選択的にキャッシュすることを検討できますが、通常、そのような決定を実装者に任せた方が適切です。

...そしてプライベートコード:非常におそらくyes。ただし、プライベートコードの場合でも、たとえばデバッグの場合など、選択的にキャッシュするのは良いことです。

とにかく、wp_cache_*関数を使用すると、データベースを汚染するリスクなしにキャッシュにアクセスできることに注意してください。

Transient APIを使用して$ related_posts配列または$ html_output文字列をキャッシュする必要がありますか?

多くのことに依存しています。文字列の大きさは?どの外部キャッシュを使用していますか?投稿をキャッシュする場合は、IDを配列として保存することをお勧めします。IDで適切な数の投稿を照会するのは非常に高速です。

最終ノート

Transient APIは、おそらくWordPressの最高の機能の1つです。あらゆる種類のキャッシュシステムで使用できるプラグインのおかげで、内部で機能する多数のソフトウェアにとって愚かな単純なAPIになります。

WordPress以外では、さまざまなキャッシングシステムを使用してすぐに動作し、1つのシステムから別のシステムに簡単に切り替えることができる抽象化を見つけるのは非常に困難です。

WordPressが他の最新のものより優れていると言うのはめったにありませんが、一時的なAPIは、WordPressで作業していないときに見逃す数少ないものの1つです。

確かにキャッシュは難しく、コードの問題を解決せず、特効薬ではありませんが、機能するトラフィックの多いサイトを構築する必要があります必要です

最適化されていないMySQLテーブルを使用してキャッシュを実行するWordPressの考え方は非常に正気ではありませんが、デフォルトでWordPressが実行しているという理由だけでキャッシュから遠ざけるのは良くありません。

あなたは物事がどのように機能するかを理解する必要があり、それからあなたの選択をします。

12
gmazzap

前の回答では、必須の「 それは依存します。 」を強調しています。これについては完全に同意します。

しかし、私がどのように「想定」を使っているかに基づいて、推奨事項を追加したいと思います。

その場合はTransientsを使わず、Post Metaを使います。後者の利点の1つは、 Control です。

投稿ごとにデータをキャッシュする必要があるため、キャッシュするデータの量は投稿の数によって異なり、時間の経過とともに増加します。一定数の投稿を超えると、オブジェクトキャッシュが使用できるメモリの制限に達する可能性があり、期限切れになる前に、以前キャッシュされたデータをメモリから消去し始めます。これは、あなたが大量の訪問者を抱えていて、それぞれの訪問者がそれぞれのページリクエストで "過度に複雑なSQL"を引き起こすという状況につながり、あなたのサイトは完全に行き詰まってしまうでしょう。

Post Metaにデータをキャッシュすると、データの格納方法と取得方法を制御できるだけでなく、データの更新方法も正確に制御できます。このために、サイトへのトラフィックが少ないかまったくない時間帯にのみ実行されるcronジョブを追加します。そのため、このサイトの実際のユーザーは「スロークエリ」に遭遇することはなく、事前にロードすることもできます。そのため、最初の訪問者がヒットしたときに作業はすでに完了しています。

キャッシュはすべてトレードオフです。それが、通常の答えが「それが依存する」である理由です。そしてなぜ「聖なるキャッシング・グレイル」がないのか。

2
Alain Schlesser