~/blog/wordpress-database-performance-optimization-guide.md
網站效能與架構優化 · 2025 / 07 / 15

WordPress 越用越慢,問題多半出在資料庫而不是主機

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
WordPress 越用越慢,問題多半出在資料庫而不是主機
目錄 table-of-contents.md

主機規格不差、圖片也壓縮了,WordPress 後台卻還是卡、前台載入慢到讓人想砸鍵盤——如果這聽起來很熟悉,瓶頸多半不在主機,而在日積月累的資料庫。網站越用越慢,往往是資料庫在拖後腿,換更貴的主機方案也只是治標。這篇帶你動手不動刀,從資料庫層根治 WordPress 的效能問題。

大家通常會直覺地把矛頭指向佈景主題或外掛,這當然是可能的原因之一。但今天,我想跟你聊聊一個更深層、更常被忽略的效能殺手——你的 WordPress 資料庫。沒錯,就是那個默默儲存你所有文章、頁面、留言和設定的地方。當它開始「鬧脾氣」的時候,你的網站速度就會直線下降。

這篇文章不是要給你一堆外掛清單叫你裝了就沒事,那是治標不治本。今天,我要帶你從根本上理解資料庫的運作原理,並提供一套從基礎清理到進階查詢優化的完整實戰策略。準備好了嗎?泡杯咖啡,讓我們開始動手不動刀,幫你的 WordPress 進行一場徹底的資料庫效能革命。

為什麼你的資料庫是網站的效能瓶頸?

在我們動手之前,先得搞懂「為什麼」。WordPress 是一個以 PHP 和 MySQL(或 MariaDB)為基礎的內容管理系統。你看到的每一個頁面,幾乎都是 PHP 向資料庫發出數個甚至數十個「查詢請求」(Query),取得資料後再組合成 HTML 呈現給你。簡單來說:

  • 資料庫查詢越快 -> 頁面生成越快 -> 網站速度飛快。
  • 資料庫查詢越慢 -> 頁面生成卡住 -> 使用者等到不耐煩。

而導致資料庫查詢變慢的常見元兇有幾個,這也是工程師最頭痛的地方:

  • 資料表臃腫: 隨著時間累積,你的資料庫塞滿了文章修訂版本、自動草稿、過期的暫存資料(Transients)、垃圾留言… 這些就像你電腦裡的垃圾檔案,佔空間又拖慢速度。
  • `wp_options` 表的隱形炸彈: 這個資料表記錄了全站的設定。有些外掛或主題會在這裡塞入大量資料,並且設定為「自動載入」(autoload)。這意味著每次頁面載入,不管用不用得到,WordPress 都會先把這些設定全部讀進記憶體,造成巨大的效能浪費。
  • 低效率的查詢: 這是最核心的技術問題。有些外掛或自訂的程式碼寫得不夠好,會產生非常複雜且沒有效率的資料庫查詢,尤其是在處理大量文章或自訂欄位(Custom Fields)時,一個爛查詢就可能讓伺服器 CPU 飆到 100%。
  • 缺乏索引(Indexing): 資料庫索引就像書本的目錄,可以讓資料庫快速找到需要的資料。如果查詢的欄位沒有建立索引,資料庫就只能一行一行地「全文掃描」,資料一多,速度自然慘不忍睹。

好了,理論課上到這邊。知道問題在哪,我們就可以對症下藥了。

第一步:資料庫大掃除,先從簡單的開始

在進行任何複雜的優化前,我們先把家裡打掃乾淨。這些操作相對安全,但老話一句,動資料庫前,務必、務必、務必備份! 這是工程師的血淚教訓,你不會想體驗的。

1. 清理無用的文章修訂(Post Revisions)

WordPress 會自動儲存你每次修改文章的版本,方便你還原。但時間一久,一篇文章可能累積數十個版本,佔用大量空間。你可以在 `wp-config.php` 檔案中加入以下程式碼來限制或關閉它:

// 限制只儲存最新的 3 個版本
define('WP_POST_REVISIONS', 3);

// 或是完全關閉 (不建議,除非你很有自信)
// define('WP_POST_REVISIONS', false);

對於已經存在的舊版本,你可以使用像 WP-Optimize 這類的外掛來清理,或是在 phpMyAdmin 中執行 SQL 指令(僅限進階使用者)。

2. `wp_options` 表的 Autoload 瘦身計畫

這是很多效能文章會忽略的重點。`wp_options` 表中有個 `autoload` 欄位,被設為 `yes` 的資料會在每個頁面載入時都被讀取。有些外掛移除後會留下垃圾設定在這裡。你可以用以下 SQL 指令找出哪些 autoload 的資料最大,看看是不是有可疑的東西:

SELECT option_name, LENGTH(option_value) AS option_value_length
FROM wp_options
WHERE autoload = 'yes'
ORDER BY option_value_length DESC
LIMIT 20;

執行後,你會看到前 20 大的 autoload 資料。如果你看到一些已經停用外掛留下的選項(通常名稱會有外掛的縮寫),可以考慮將它的 `autoload` 值從 `yes` 改成 `no`,或直接刪除該行。再次警告:亂動這裡可能導致網站崩潰,請確認你知道你在刪什麼。

第二步:查詢的藝術,讓 `WP_Query` 跑得飛快

清理完畢,接下來是重頭戲。身為開發者,我們最常跟 `WP_Query` 打交道。一個小小的參數調整,效能可能天差地遠。這部分有點硬核,但保證值得。

`WP_Query` 效能參數大補帖

當你在寫一個自訂查詢時,問問自己:「我真的需要所有資料嗎?」根據你的需求,加上以下參數,可以大幅減少資料庫的負擔:

  • 'no_found_rows' => true:預設情況下,`WP_Query` 會計算符合條件的總文章數,以供分頁使用。如果你的查詢不需要分頁功能,加上這個參數可以跳過這個耗時的計算步驟。
  • 'update_post_meta_cache' => false:如果你在迴圈中不會用到 `get_post_meta()` 或其他自訂欄位函數,設定這個為 `false` 可以避免 WordPress 預先載入所有文章的 meta data。
  • 'update_post_term_cache' => false:同上,如果不需要文章的分類、標籤等資訊,就關掉它。
  • 'fields' => 'ids':這是終極大絕招。如果你的目的只是要取得符合條件的文章 ID 列表,而不是整個文章物件,使用這個參數。回傳的只會是一個 ID 陣列,效能提升是數量級的差異。

來看看一個高效查詢的範例:

$args = array(
    'post_type'      => 'product',
    'posts_per_page' => 10,
    'meta_key'       => 'is_featured',
    'meta_value'     => 'yes',
    // --- 效能優化參數 --- //
    'no_found_rows'          => true, // 我不需要分頁
    'update_post_meta_cache' => false, // 我不會在迴圈裡用 get_post_meta
    'update_post_term_cache' => false, // 我也不需要分類資訊
);

$featured_products = new WP_Query($args);

養成在寫 `WP_Query` 時思考這些參數的習慣,你的網站會感謝你。

第三步:快取是你的超級武器

「不要重複做一樣的事」是工程師的核心信仰。快取(Cache)就是這個信仰的具體實踐。與其每次都去問資料庫這個又慢又累的傢伙,不如把問過的結果先記在一個速度飛快的地方(例如記憶體),下次再有人問就直接給答案。

1. 物件快取(Object Caching)

WordPress 內建一個基本的物件快取機制,但它只在單次頁面載入的生命週期內有效。要真正發揮威力,你需要一個持續性的後端,例如 RedisMemcached。在伺服器上安裝好 Redis 後,再安裝像是 Redis Object Cache 這類的外掛,並在 `wp-config.php` 中設定好連線資訊,就能啟用強大的物件快取。

啟用後,許多重複的資料庫查詢(例如網站設定、導覽選單等)會被快取在記憶體中,大幅降低資料庫負載,網站回應速度會有肉眼可見的提升。對於任何有一定流量的網站來說,這幾乎是標配。

2. Transients API 的妙用

如果你有一段程式碼需要執行一個非常複雜的查詢或呼叫外部 API,你絕對不希望它在每次頁面載入時都執行一次。這時候,WordPress 內建的 Transients API 就是你的好朋友。它可以讓你把任何資料片段設定一個過期時間,並儲存在資料庫(或如果你有啟用物件快取,會存在記憶體中)。

看看這個範例,我們快取一個複雜的產品查詢結果 12 小時:

function get_my_complex_product_data() {
    // 1. 先試著從快取(Transient)拿資料
    $product_data = get_transient('complex_product_data');

    // 2. 如果快取沒有,才執行真正的查詢
    if (false === $product_data) {
        // 這裡是你原本耗時的資料庫查詢或 API 呼叫
        $product_data = new WP_Query( /* ... 你的超複雜 args ... */ );

        // 3. 把查詢結果存回快取,設定 12 小時後過期
        set_transient('complex_product_data', $product_data, 12 * HOUR_IN_SECONDS);
    }

    // 4. 回傳資料(無論是來自快取還是新查詢的)
    return $product_data;
}

善用 Transients API,是衡量一個 WordPress 開發者是否專業的重要指標之一。

總結:效能優化是一條持續的道路

WordPress 資料庫效能優化不是一個裝了外掛就一勞永逸的工作,它更像是一種開發習慣和持續的維護過程。我們今天從最基礎的資料庫清理,談到核心的 `WP_Query` 參數優化,再到利用快取機制來避免不必要的資料庫負載。

記住四大心法:清理(Clean)、查詢(Query)、快取(Cache)、索引(Index)。掌握了這些原則,你就掌握了讓 WordPress 網站飛起來的關鍵。當然,資料庫索引是更進階的話題,需要對 MySQL 有更深的理解,但光是做好前三項,你的網站效能就已經能超越 90% 的對手了。

希望今天的分享對你有幫助。身為工程師,最大的樂趣莫過於看到自己手下的系統跑得又快又穩。動手試試看吧!


延伸閱讀

需要專業協助嗎?

覺得資料庫優化太過複雜,或是有更棘手的 WordPress 效能問題需要解決嗎?浪花科技的團隊擁有多年的 WordPress 深度開發與效能調校經驗。我們樂於協助你打造一個穩定、快速且安全的網站。歡迎點擊這裡填寫表單,與我們的專家聊聊!

// FAQ

常見問題

WordPress 網站變慢,除了主機和圖片之外還可能是什麼原因?
資料庫往往是被忽略的效能瓶頸。WordPress 每次產生頁面都會向 MySQL/MariaDB 發出數個甚至數十個查詢,當資料表臃腫、查詢缺乏效率或欄位沒有索引時,查詢變慢就會直接拖慢頁面生成速度。常見元兇包括文章修訂版本過多、過期暫存資料、wp_options 表的 autoload 資料過大,以及缺乏索引導致的全表掃描。
如何限制或關閉 WordPress 的文章修訂版本(Post Revisions)?
在 wp-config.php 中加入 define('WP_POST_REVISIONS', 3); 可限制每篇只保留最新 3 個版本,或設為 false 完全關閉自動修訂。對於資料庫中已累積的舊版本,可用 WP-Optimize 這類外掛清理,或在 phpMyAdmin 執行 SQL 指令。動資料庫前務必先備份。
wp_options 表的 autoload 為什麼會影響網站效能?
autoload 欄位被設為 yes 的資料,會在每一次頁面載入時全部被讀進記憶體,不論該頁是否用得到。有些外掛移除後會在這裡留下垃圾設定,導致每次載入都浪費資源。可用 SQL 查出最大的 autoload 資料,將不需要的選項改為 no 或刪除,但需確認清楚再動,以免網站崩潰。
WP_Query 有哪些參數可以提升查詢效能?
若查詢不需要分頁,加上 'no_found_rows' => true 可跳過總筆數計算;若迴圈中不用自訂欄位,設 'update_post_meta_cache' => false;不需分類標籤則設 'update_post_term_cache' => false。若只需要文章 ID 列表,使用 'fields' => 'ids' 可帶來數量級的效能提升。
WordPress 要如何用快取降低資料庫負載?
可安裝持續性的物件快取後端如 Redis 或 Memcached,搭配 Redis Object Cache 外掛,將網站設定、選單等重複查詢快取在記憶體中。對於耗時的複雜查詢或外部 API 呼叫,則可用內建的 Transients API 設定過期時間暫存結果,避免每次頁面載入都重新執行。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

把 AI 自動化、企業系統設計與 WordPress / Laravel 開發的真實案例和可直接照做的技巧,整理成電子報寄給你。只寄精選內容、不灌垃圾信,一鍵就能退訂。

$
// final.exec()

準備好讓你的網站開始為你工作了嗎?