~/blog/wordpress-mysql-index-tuning-explain-guide.md
網站效能與架構優化 · 2025 / 07 / 22

MySQL 索引調教實戰:用 EXPLAIN 揪出拖慢網站的真正元兇

Eric — 浪花科技創辦人 / AI 架構師
Eric
浪花科技創辦人 · AI 架構師
MySQL 索引調教實戰:用 EXPLAIN 揪出拖慢網站的真正元兇
目錄 table-of-contents.md

在我們的開發日常中,最常聽到的客戶求救訊號就是:「我的網站好慢,怎麼辦?」接著,他們會列出一長串已經做的努力:買了更貴的主機、裝了快取外掛、圖片也壓到最小了... 但網站的後台操作,或是某些特定頁面,依然慢得像在演慢動作電影。

身為一個天天跟程式碼和伺服器打交道的工程師,我得告訴你一個殘酷的事實:很多時候,你網站的瓶頸根本不在前端,而是那個默默在背後工作,卻又最容易被忽略的功臣——MySQL 資料庫。當你的資料庫開始「罷工」,查詢效率低落時,再強大的主機、再完美的快取,都只是治標不治本。今天,我就要帶你拿起外科手術刀,深入 WordPress 的心臟,透過 MySQL 索引優化與效能調教,揪出那些讓網站龜速的元兇,讓你的網站速度重獲新生。

為什麼你的 WordPress 像開著手煞車在跑?元兇:資料庫查詢

要理解問題,得先搞懂 WordPress 是怎麼運作的。簡單來說,每當有人訪問你的網站,WordPress 的 PHP 程式碼就會向 MySQL 資料庫發出一連串的「查詢請求」,像是:「請給我最新十篇文章」、「請找出所有分類是『技術教學』的文章」、「這位使用者是誰?他有什麼權限?」。

想像一下,你的資料庫是一座巨大的圖書館,而文章、頁面、使用者資料就是裡面的書。如果這座圖書館沒有索引目錄卡,你要找一本書,就只能一本一本地翻,直到找到為止。當你的網站內容還很少(圖書館只有幾十本書)時,這不是問題。但隨著文章、商品、會員數量越來越多(圖書館藏書變成數十萬冊),每一次的「大海撈針」都會變成一場災難。

這就是「沒有索引」的資料庫查詢。MySQL 會進行所謂的「全表掃描」(Full Table Scan),把整張資料表從頭到尾讀一遍,來找到你需要的資料。這不僅耗費大量時間,也佔用大量的 CPU 和記憶體資源,你的網站自然就慢下來了。

常見的慢查詢場景:

  • 複雜的 WP_Query:例如,你可能需要撈出「特定分類下、包含特定標籤、且擁有某個自訂欄位值」的文章。這種多條件查詢,如果沒有適當的索引,效能會非常差。
  • 寫得不好的外掛:有些外掛為了實現特定功能,會產生非常沒有效率的資料庫查詢,在你的網站上埋下效能地雷。
  • WooCommerce 網站:電商網站的資料庫查詢更加複雜,涉及訂單、顧客、商品屬性等,是慢查詢的重災區。

偵探工具上手:用 EXPLAIN 揪出拖垮網站的慢查詢

好吧,理論講完了,我們來點實際的。要進行 MySQL 索引優化與效能調教,第一步就是要找出那些「慢查詢」。口說無憑,我們需要數據證據。

第一步:安裝 Query Monitor 外掛

在 WordPress 的世界裡,Query Monitor 是每個開發者都該裝的神器。它會在你的網站上方顯示一個管理列,清楚列出每個頁面載入時執行的所有資料庫查詢、它們花了多少時間,以及是哪個外掛或主題觸發的。當你發現某个查詢花了零點幾秒甚至更久,恭喜你,你找到嫌疑犯了!

第二步:讓 EXPLAIN 告訴你真相

找到慢查詢的 SQL 語句後,我們就要請出今天的主角:EXPLAIN 指令。EXPLAIN 可以分析 MySQL 會如何執行你的查詢,就像是讓 MySQL 給你一份「執行計畫書」。

你可以使用 phpMyAdmin、Adminer 或任何資料庫管理工具,在你的 SQL 查詢語句前加上 EXPLAIN 關鍵字,然後執行。例如:

EXPLAIN SELECT * FROM wp_posts WHERE post_author = 1 AND post_type = 'post';

執行後,你會看到一個表格,裡面有很多欄位,但你只需要先專注在幾個關鍵欄位上:

  • type:這是最重要的欄位,代表 MySQL 存取資料表的方式。你的目標是讓它盡可能地好(從上到下)
    • const / system:最理想的狀況,通常是查詢主鍵或唯一索引。
    • eq_ref:也很棒,常用於 JOIN 操作。
    • ref:不錯,使用非唯一性索引進行查找。
    • range:還行,對索引進行範圍掃描。
    • index:不太妙,掃描了整個索引樹。
    • ALL紅色警戒!這就是我們前面說的「全表掃描」,MySQL 正在遍歷整張表,是效能殺手。
  • possible_keys:MySQL 認為「可能」可以使用的索引。
  • key:MySQL 「實際」決定使用的索引。如果這裡是 NULL,而 typeALL,那問題就大了。
  • rows:MySQL 預估需要掃描的資料行數。這個數字越小越好。
  • Extra:額外資訊。如果看到 Using filesortUsing temporary,通常代表查詢有很大的優化空間,因為 MySQL 需要在記憶體或硬碟中建立臨時表來處理排序,這非常耗效能。

身為工程師,看到 type: ALL 的感覺,就像看到程式碼裡有個不定時炸彈一樣,你得立刻拆除它。

手術開始:MySQL 索引優化與效能調教實戰

理論和工具都備齊了,我們來動刀吧!假設我們透過 Query Monitor 發現一個由某個外掛產生的慢查詢,目的是為了找出所有meta key為 _stock_status 且 meta value 為 instock 的商品:

SELECT post_id FROM wp_postmeta WHERE meta_key = '_stock_status' AND meta_value = 'instock';

我們把這段 SQL 拿去 EXPLAIN,很可能會看到 type: ALL,而且 rows 是一個巨大的數字,因為它正在掃描整個 `wp_postmeta` 資料表。

問題分析: 查詢條件是 `meta_key` 和 `meta_value` 兩個欄位,但 WordPress 預設的索引可能不適合這種組合查詢。我們需要一個「複合索引」(Composite Index)來同時涵蓋這兩個欄位。

解決方案: 我們來手動建立一個索引。

ALTER TABLE wp_postmeta ADD INDEX idx_meta_key_value (meta_key, meta_value);

這個指令的意思是:在 `wp_postmeta` 這張表上,新增一個名為 `idx_meta_key_value` 的索引,這個索引包含了 `meta_key` 和 `meta_value` 兩個欄位。

工程師小囉嗦:在上面的 SQL 中,有時候你會看到像 `meta_key(191)` 這樣的寫法。這是因為舊版的 MySQL 對於使用 `utf8mb4` 編碼的欄位,索引長度有限制。加上長度限制是個好習慣,可以避免未來遇到相容性問題。

加上索引後,我們再次執行同一個 `EXPLAIN` 指令:

EXPLAIN SELECT post_id FROM wp_postmeta WHERE meta_key = '_stock_status' AND meta_value = 'instock';

神奇的事情發生了!你會發現 typeALL 變成了 refkey 欄位顯示了我們剛剛建立的 `idx_meta_key_value`,而 `rows` 的數量也大幅下降。這代表 MySQL 現在可以直接透過索引快速定位到符合條件的資料,而不是傻傻地掃描全表。你的查詢速度可能從幾秒鐘縮短到幾毫秒!

工程師的最後提醒:索引不是越多越好

看到這裡,你可能會想:「太神了!那我把所有欄位都加上索引不就好了?」打住!千萬別這麼做。這也是 MySQL 索引優化與效能調教 中最常見的誤區。

記住,天下沒有白吃的午餐。索引的代價是:

  • 儲存空間: 索引本身也需要佔用硬碟空間。
  • 寫入效能降低: 每當你新增(INSERT)、更新(UPDATE)或刪除(DELETE)一筆資料時,MySQL 不僅要修改資料本身,還要同步更新所有相關的索引。索引越多,寫入操作就越慢。

所以,索引的建立原則是「精準」而非「多」。只在真正需要查詢的欄位(通常是 WHERE, JOIN, ORDER BY 子句中用到的欄位)上建立索引。對於那些很少被查詢,或是欄位值重複性非常高(例如「性別」這種只有兩三種值的欄位,我們稱為低基數性 Cardinality),建立索引的效益就不大。

結論:讓你的資料庫從「罷工」變「火箭」

網站效能優化是一個系統工程,但資料庫絕對是其中最核心、也最容易被忽略的一環。下次當你的 WordPress 網站又開始慢吞吞時,別急著怪主機或升級方案。學會使用 Query Monitor 和 EXPLAIN,像個偵探一樣找出效能瓶頸,並用索引這把手術刀精準地解決問題。

這套 MySQL 索引優化與效能調教 的方法,不僅能讓你的網站速度飛起來,更能讓你對 WordPress 的底層運作有更深刻的理解。這才是從「網站管理員」晉升為「技術專家」的關鍵一步。

當然,資料庫優化是個深水區,涉及的層面遠不止於此。如果你在實作中遇到困難,或是有更複雜的效能問題需要處理,浪花科技的團隊隨時準備好為你提供專業的協助。

延伸閱讀

對深入的 WordPress 效能調校或客製化開發有興趣嗎?覺得自己的網站卡關了,需要專業的技術團隊為你開路?歡迎點擊這裡,填寫表單與我們聯繫,讓浪花科技的技術專家為你的網站進行全面健檢,打造真正高效能的數位體驗!

// FAQ

常見問題

WordPress 網站變慢,為什麼瓶頸常常是資料庫而不是前端?
每次有人訪問網站,WordPress 的 PHP 程式碼都會向 MySQL 發出一連串查詢請求。當文章、商品或會員數量龐大且缺少適當索引時,MySQL 必須做「全表掃描」逐筆讀完整張表,耗費大量時間與 CPU、記憶體資源。此時再強的主機或快取都只是治標,真正的瓶頸在資料庫查詢效率。
如何找出拖慢 WordPress 的慢查詢?
先安裝 Query Monitor 外掛,它會列出每個頁面載入時執行的所有資料庫查詢、各自花費的時間,以及是哪個外掛或主題觸發的,藉此鎖定耗時的查詢。接著把該段 SQL 語句加上 EXPLAIN 關鍵字執行,讓 MySQL 給你一份執行計畫書,分析它實際如何取得資料。
用 EXPLAIN 分析查詢時,哪些欄位最該注意?
最重要的是 type 欄位,代表 MySQL 存取資料表的方式,由好到壞大致為 const/system、eq_ref、ref、range、index、ALL;看到 ALL 就代表正在做全表掃描,是效能殺手。其次看 key(實際使用的索引)、rows(預估掃描的列數,越小越好),以及 Extra 欄位若出現 Using filesort 或 Using temporary,通常代表還有很大的優化空間。
查詢同時用到 meta_key 和 meta_value 兩個條件,該怎麼建索引?
可以建立一個同時涵蓋兩個欄位的「複合索引」,例如 ALTER TABLE wp_postmeta ADD INDEX idx_meta_key_value (meta_key, meta_value);。加上索引後再次 EXPLAIN,type 通常會從 ALL 變成 ref、掃描列數大幅下降,查詢可能從數秒縮短到數毫秒。針對 utf8mb4 編碼的舊版 MySQL,必要時可加上長度限制如 meta_key(191) 以避免索引長度限制問題。
MySQL 索引是不是建越多越好?
不是。索引會佔用額外的硬碟空間,而且每次 INSERT、UPDATE、DELETE 資料時 MySQL 都要同步更新所有相關索引,索引越多寫入越慢。建立原則是「精準」而非「多」,只在 WHERE、JOIN、ORDER BY 真正用到的欄位上建立;對於很少被查詢、或值的重複性極高(低基數性)的欄位,例如只有兩三種值的性別欄位,建索引效益不大。
~/roamer-tech/newsletter // FREE
// newsletter

訂閱免費電子報

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

$
// final.exec()

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