問題描述
我正在為一家公司工作,該公司將很有可能透過自定義職位型別建立數百萬個職位。他們是禱告,所以基本上前端的使用者只需透過表單提交一個短語。所有公司都關心的是釋出內容和釋出日期。該網站還沒有啟動,他們已經有超過 12 萬個職位,所以當我說數百萬的時候,我死了嚴重。
所以,幾個最佳化問題:
-
假設我有一個自定義帖子型別中有一個類別’featured’,其中有 50 萬個帖子。特色類別只有 500 個帖子。如果我為特色帖子建立了一個查詢,我查詢了整個 50 萬個帖子,還是僅檢視了 500 個帖子?如果我只想顯示十個最近釋出的帖子怎麼辦?
-
將此自定義帖子型別儲存到資料庫時,有什麼事情可以減少伺服器資源,特別是因為唯一真正需要的是帖子和日期的內容?
-
我是否應該使用自定義帖子型別?我原則上喜歡它,因為它很好地整合到 WordPress 管理員中,但是如果效能有很大的缺點,那麼我想我可以做不同的事情。
我從來沒有在這個規模的專案上工作,所以我比平時更關心效能。感謝任何幫助!
最佳解決方案
1. WP_Query 執行前設定查詢
當嘗試將資料庫查詢保持在最小值時,這似乎是最重要的事情,因為修改查詢的唯一機會當然是在 SQL 資料庫中執行之前。
正常查詢對於正常查詢,WordPress 使用 wp()函式,後者又呼叫 $wp->main( $query_vars )。來自條件標籤的 「is_變數」 在將它們傳遞給 WP_Query->get_posts()之前設定,它將其轉換成 MySQL 資料庫查詢,最後將它們儲存在 $ wp_query 物件中。在 SQL database 中實際執行查詢之前,可以過濾查詢。
pre_get_posts 操作掛接到此過程中,允許您將查詢更改為傳遞給 WP_Query->get_posts()之前。
例如,如果要過濾”featured” 類別中的帖子的查詢,您將使用 add_action( 'pre_get_posts', 'your_function_name' ); 並在 your_function_name 中包含 in_category 條件標籤。
function your_function_name( $query ) {
if ( $query->in_category( 'featured' ) && $query->is_main_query() ) {
// Replace 123 with the category ID of the featured category.
$query->set( 'cat', '123' );
}
}
add_action( 'pre_get_posts', 'your_function_name' );
見 Plugin API/Action Reference/pre get posts « WordPress Codex
頁面請求對於頁面模板,例如”featured” 類別的歸檔頁面,條件標籤將無法從 pre_get_posts 過濾器工作。例如,由於 WP_Query 尚未執行,因此無法使用 is_category 來檢查存檔頁面。
相反,您必須使用 new WP_Query 更改頁面請求的主要查詢,如 $query = new WP_Query( 'cat=123' ); 。這將從開始執行具有適當引數的查詢。
見 Class Reference/WP Query « WordPress Codex
2. 儲存到資料庫
您可以使用過濾器 wp_insert_post_data 確保僅將與您的自定義職位型別相關的 $資料返回給 wp_insert_post 。確保包含條件語句以檢查您的自定義帖子型別。 Plugin API/Filter Reference/wp insert post data « WordPress Codex
此鉤子由 wp_insert_post 函式呼叫,當您更新自定義帖子型別時,通常透過儲存草稿或釋出帖子,wp_update_post 呼叫該函式。
您必須自己進行基準測試,因為我無法親自說出減少資料庫中更新的資料的最佳化意義。
自定義帖子型別會影響效能嗎?
根據我的經驗,自定義帖子型別是管理內容的強大工具。我不知道有什麼其他方式來管理釋出的所有方式,它允許使用較少的資源。我個人會專注於盡可能減少查詢次數的方法。
以前是一個與永久連結結構相關的效能問題,導致它以文字而不是數字開始時受到打擊。 3 對於託管大量頁面的網站來說,這是特別麻煩的,但是自 WordPress 版本 3.3 起已經解決了。
我只是在這裡提出了永久連結,因為 lug is 通常是固定連結結構的第一部分,可能或可能不會影響版本 3.3 之前的效能。除此之外,我不知道使用自定義帖子型別引起的任何效能問題。
其他效能選項
瞬態這不是替代您的程式碼中的最低限度的查詢,但您可以使用 set_transient 儲存查詢一段時間,以便不需要新的查詢。以下是 Dave Clements’ post 中使用的示例。此外,請注意,他建議在每次更新給定的帖子型別時,新增一個 save_post 操作來刪除該暫態。
<?php // IN THE SPOTLIGHT QUERY
if( false === ( $its_query = get_transient( 'its_query' ) ) ) {
$pttimestamp = time() + get_option('gmt_offset') * 60*60;
$its_query = new WP_Query( array(
'post_type' => 'spotlight',
'posts_per_page' => 1,
'post__not_in' => $do_not_duplicate,
'meta_query' => array(
array(
'key' => '_hpc_spotlight_end_time',
'value' => $pttimestamp,
'compare' => '>'
)
)
) );
set_transient( 'its_query', $its_query, 60*60*4 );
}
if( have_posts() ) { // HIDE SECTION IF NO CURRENT ITS FEATURE ?>
// LOOP GOES HERE: NOT IMPORTANT TO EXAMPLE
<?php } ?>
更多查詢最佳化 Thomas Griffin 在他的 Optimize WordPress Queries 教程中有幾個很好的提示。以下是他的建議的簡要列表:
-
設定’cache_results’ => 如果您的伺服器不使用永續性快取 (如 Memcached),則在 one-off 中查詢是否為 false 。 One-off 查詢被描述為 「用於顯示少量資料的查詢,可能是您只想顯示與當前帖子相關的連結的帖子,或者您可能需要顯示一個下拉式清單以選擇特定的選項設定 「。他的例子:$ query = get_posts(array(‘posts_per_page’ => 1,’cache_results’ => false));
-
設定’no_found_rows’ => 真的不需要分頁。這將 「繞過 MySQL 計算結果,看看我們是否需要分頁。」 他的例子:$ query = new WP_Query(array(‘posts_per_page’ => 1,’no_found_rows’ => true));
-
只有在
get_posts中需要'fields' => 'ids'的情況下才能查詢帖子 ID 。這應該顯著減少返回的資料量,如果你看看 Database Description « WordPress Codex 他的例子,這是相當多的:$query = get_posts( array( 'posts_per_page' => 1,
'fields' => 'ids' ) );
除了最後一個提示,當您只需要使用 get_post_field 只需要一個或幾個後期欄位時,也可以應用相同的推理。
瞭解查詢的工作原理是非常重要的。您的查詢越具體,您從 SQL 資料庫中要求的工作越少。這意味著管理資料庫查詢的可能性很大。使用自定義查詢,直到它們執行的位置 (是管理頁面嗎?),在直接查詢中使用正確的 sanitization,並嘗試使用本機 WordPress 功能,讓您能夠實現相同的效能。
參考文獻
注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。