多數人一聽到網站變慢,第一個念頭是資料庫裡塞了太多文章、留言或圖片,資料量一多,查詢自然慢下來。實際情況常常不是這樣。真正每次頁面請求都在拖慢速度的,往往是資料庫裡一張不起眼的表,叫 wp_options,以及裡頭一個叫 autoload 的欄位,也就是這篇要拆解的 wp_options autoload 問題。
這張表存的是網站網址、管理員信箱、每支外掛與布景主題的設定,以及一些暫存資料,乍看沒什麼特別。但 autoload 欄位一旦被標記,這筆設定就會在每一次有人打開你的網站時,整包被撈進記憶體,不管這次請求用不用得到它。外掛越裝越多,這包每次都要重讀一遍的資料只會越養越大,而且大多數時候站長完全不知情,直到網站慢到讓人受不了,或更嚴重直接打不開,才會回頭查是哪裡出了問題。
autoload 是什麼?
wp_options 表本身沒有特別複雜,結構就四個欄位:option_id 是流水號、option_name 是設定的名稱(像是網站標題、時區、外掛版本號)、option_value 存實際的值,而 autoload 就是這篇的主角,決定這筆資料要不要在每一次頁面請求時被自動撈出來。表裡存的資料大致分三類:站台本身的基本設定(網址、管理員信箱、時區)、每支外掛與布景主題各自寫進去的設定值,以及一些暫時性的快取資料。
WordPress 設計 autoload 這個機制,原本是為了效能,不是拖累效能。WordPress 核心開發團隊在 2024 年 6 月發布於 Make WordPress Core 部落格的文章中說明,WordPress 會用單一一次查詢,把所有標記為需要自動載入的選項一次讀出來,這個技術稱為 autoloading,目的是避免每個設定都要各自單獨查一次資料庫,單獨查詢的成本反而更高。換句話說,把常用的設定打包成一次撈取,原本是聰明的效能設計。
問題出在打包的東西越養越多。核心團隊同一篇文章也直接點出代價,自動載入大量沒有真的被用到的資料,一樣會拖累網站效能。網站慢下來,通常不是資料庫裡文章、留言筆數本身太多,而是這包每次都要重讀一遍的資料本身養胖了,autoload 的資料量跟資料庫的整體大小,根本是兩件事。搞清楚這個差異,才知道接下來該查哪裡,而不是急著去清文章或圖片附件。

wp_options 資料量失控的 3 個常見成因
autoload 資料為什麼會不斷長大,追根究柢都跟外掛脫不了關係,但表現方式不只一種,大致可以分成三種常見成因,實際遇到卡站或效能不佳,通常是其中一種在作怪,有時候甚至三種同時發生。
第一種是外掛把不需要每一頁都用到的設定,也設成自動載入。國際主機平台 Kinsta 在分析這個問題時舉的例子很直接,一支聯絡表單外掛,實際上只有訪客打開聯絡頁時才需要讀取它的設定,卻被外掛開發者設成整站每一頁都自動載入,等於讓絕大多數跟聯絡表單無關的頁面,平白多背一份用不到的資料。
第二種是外掛或布景主題被移除以後,它先前寫進 wp_options 的設定沒有被一併清掉,變成查無主人的殘骸。同一份分析指出,外掛或主題已經從網站移除,但設定仍然留在 wp_options 表裡,結果是每一次請求都在查詢一批根本不會再被任何程式碼用到的自動載入資料,這是三種成因裡最容易被忽略的一種,因為後台介面看不到「已刪除外掛的殘留設定」這種清單,得靠後面幾節教的方法自己揪出來。
第三種比較根本,問題出在外掛開發者的資料庫設計。有些外掛需要持續累積的資料,像是逐筆的操作紀錄或一大包陣列資料,本來就該用外掛自己建立的資料表存放,卻被開發者直接寫進 wp_options。文中也特別提醒,wp_options 表的設計初衷並不是拿來存放成千上萬筆資料列的地方;如果開發者又把這些資料全塞進單一一個 option,這一筆的內容量就會持續往上疊加,不用等到外掛裝了幾十支,光是這一筆資料自己就能讓 autoload 膨脹。
三種成因造成的結果一樣,autoload 都會越養越大,但排查的方向不同:第一種要回頭看外掛設定選項,第二種要比對現有外掛清單抓殘骸,第三種則要留意有沒有單一一筆資料本身就異常肥大。
自動載入資料超過快取上限,網站直接打不開
多數人以為 autoload 資料養大了,頂多讓網站變慢一點,反正現在網路速度普遍不差,慢個零點幾秒感覺不出來。這個假設在沒有物件快取的站台上大致成立,但如果你的網站用的是 Memcached 這類對單一物件設有大小上限的物件快取,情況就完全不同,autoload 資料不是慢下來,而是可能直接讓網站打不開。
原因在於物件快取儲存 autoload 這包資料的方式。有物件快取時,整包自動載入資料會被存成快取系統裡的單一一個物件,通常稱為 alloptions。Memcached 對單一物件的大小設有上限,Automattic 旗下的企業級 WordPress 平台 WP VIP 在自家文件裡就明確寫出這個數字,在 WP VIP,所有 Memcached 物件都有 1MB(壓縮後)的大小上限,而這個上限一樣適用於 alloptions 快取的內容。
同一份文件指出,alloptions 的問題最常發生在它的大小逼近 1MB 上限的時候,後果不只是某次查詢慢一點,而是整個網站的效能都受到拖累;情況再惡化下去,網站甚至會在問題根源被解決之前變成不可用,在 WP VIP 上,受影響的網站會回傳 HTTP 503 狀態碼,並顯示「Error 1024 (alloptions)」的錯誤畫面。
這個變化通常是漸進發生的,不是裝了某支外掛的隔天網站就掛掉。autoload 資料一點一滴累積,可能經過好幾個月都沒人注意,直到某次資料量剛好跨過快取物件的大小上限,網站才突然出狀況。多數站長遇到的第一個線索,往往是網站流量沒變、卻開始間歇性打不開,而且錯誤畫面看起來跟一般的伺服器問題不太一樣,這正是回頭檢查 autoload 資料量的時機。
Site Health 與 Performance Lab 的自動載入檢查
不想一開始就碰資料庫或指令列,也有現成的方法可以先掌握概況。WordPress 核心與生態圈裡有兩個工具,分別從不同角度呈現自動載入資料的狀況:一個是後台內建、不用裝任何東西的網站狀態頁,另一個是 WordPress 效能團隊釋出的 Performance Lab 外掛,會在同一頁補上個別選項的大小清單。兩者都是在後台查看,除非你自己按下停用按鈕,否則不會動到資料庫裡任何一筆資料,適合當作第一步。
Site Health 網站狀態頁的自動載入警示門檻
這項檢查從 WordPress 6.6 開始內建在核心,不需要額外安裝外掛,中文後台從「工具→網站狀態」就能看到。WordPress 核心開發團隊在 Make WordPress Core 部落格說明,網站狀態新增了一項檢查,只要自動載入選項的總大小超過 800 KB,就會顯示一則「重大問題」等級的提示;核心原始碼裡的門檻寫的是 800,000 位元組,中文後台的提示標題是「自動載入選項會影響效能」,說明文字會寫出站上目前有幾個自動載入選項、總大小是多少。沒超過門檻時,這一項會列在「已通過的測試」裡,標題是「自動載入選項在可接受範圍內」,一樣附上數量與大小。
這則提示的用意是提早示警,不是等到網站真的打不開才讓你知道。800 KB 這個門檻本身不算高,一個中大型網站裝了十幾二十支外掛,加上幾個常見的頁面建置工具,並不難超過這個量。看到這則「重大問題」也不用太緊張,它代表的是該花時間查一下了,不是網站已經出狀況。要注意的是,核心這項檢查只給總數與總大小,不會列出是哪幾筆選項佔最多。
Performance Lab 外掛列出的前 20 大自動載入選項
想知道是哪幾筆資料把總量撐大,核心團隊在同一篇文章裡提到可以安裝 Performance Lab 外掛,它會在網站狀態的自動載入檢查裡補上詳細的選項清單。依 Performance Lab 目前釋出版本的原始碼,這份清單會挑出大於 100 位元組的自動載入選項,依大小由大到小排序、最多列出 20 筆,每一筆後面都有一個「停用自動載入」按鈕,按下去只會把這筆設定改成不自動載入,資料本身還在;停用過的選項會另外列成一張表,隨時可以按「還原為自動載入」改回來。
這份清單是附在核心那則「重大問題」提示底下的,也就是總量超過門檻時才會出現;總量還在可接受範圍內,網站狀態頁就只會顯示通過的那一項。清單上的選項名稱,可以直接拿去對照後面「正常、異常與殘骸」那一節的判讀方式,先確認屬於哪一類再決定要不要按停用,核心必要的選項不要在這裡順手關掉。另外,WP VIP 平台上的 Query Monitor 也有一個 Autoloaded Options 面板能看到類似的排行,但一般主機從外掛目錄安裝的 Query Monitor 沒有這個面板。
SQL 與 WP-CLI 查出的總量與最大幾筆選項
Site Health 與 Performance Lab 適合先抓概況,但如果你有主機的資料庫或終端機權限,直接用 SQL 查詢或 WP-CLI 指令,能拿到更精準、也更方便拿去比對歷史紀錄的數字。實際操作前建議先確認自己有資料庫的存取權限,或至少先在測試環境跑過一次。
計算總量的 SQL 查詢與新版 autoload 值的差異
網路上流傳的 wp_options 查詢範例,絕大多數寫法只抓 autoload = 'yes',在比較新的 WordPress 版本上,這樣算出來的總量會偏低,判斷因此失準。
原因在於 autoload 欄位這幾年已經擴充過。舊版本裡,autoload 只有 yes 與 no 兩種值;WordPress 核心開發團隊在同一篇文章說明,較新的資料列可以儲存 on、off、auto、auto-on 或 auto-off,而舊有的 yes 與 no 資料列仍然可以正常運作,兩者是相容的。核心目前會把 yes、on、auto-on 與 auto 都視為需要自動載入,只有 off、auto-off 與 no 才是真的不自動載入。核心團隊也提供了一支核心函式 wp_autoload_values_to_autoload(),會回傳資料庫中所有應被視為需要自動載入的值,預設就是包含 yes、on、auto-on 與 auto 的陣列。
只查 autoload = 'yes' 的舊寫法,會漏掉新版本產生的 on、auto、auto-on 這幾種同樣會被自動載入的資料,算出來的總量因此偏低,容易誤判自己的站其實還好。要拿到準確數字,查詢時就要把這幾種值都涵蓋進去:
SELECT SUM(LENGTH(option_value)) AS total_bytes
FROM wp_options
WHERE autoload IN ('yes', 'on', 'auto-on', 'auto');Code language: SQL (Structured Query Language) (sql)
這支查詢會回傳目前站上所有真正會被自動載入的資料,加總起來的位元組數。跟前面 Site Health 的門檻對照,就能知道自己的站落在哪個區間;核心的門檻是 800,000 位元組,直接拿位元組數去比最準,除以 1024 換算成 KB 只是方便閱讀,換算後大約 781 KB 就已經到門檻。
WP-CLI 一行指令算出的自動載入總位元組數
如果主機開放終端機、也裝有 WP-CLI,不用寫 SQL 也能拿到總量數字,但它跟上一節提到的新版 autoload 值並沒有完全對齊。依 WP-CLI 的原始碼,--autoload=on 實際只比對 on 與 yes 兩種值,不含同樣會被自動載入的 auto 與 auto-on,而新版 WordPress 裡外掛沒特別指定就寫入的設定,多半就存成 auto,所以算出來的數字可能比上一節的 SQL 低;另外 wp option list 預設不計入 _transient_ 與 _site_transient_ 開頭的暫存資料,就算其中有會被自動載入的,也不會算進這個總量。WP-CLI 指令文件給出的範例是:
wp option list --autoload=on --format=total_bytesCode language: Bash (bash)
--autoload 這個參數的定義是,當值為 on 時只比對自動載入的選項,值為 off 時只比對不自動載入的選項;文件裡的範例輸出是 33198,單位是位元組,換算下來大約是 32 KB。輸出只有一個數字,沒有附單位,自己拿計算機除以 1024 換算成 KB 就好;要拿去跟 800 KB 門檻比,或做前後比對,還是以上一節涵蓋全部值的 SQL 為準。
想進一步看到個別選項的大小排行,同一支 option list 指令有一個 size_bytes 欄位,用 --fields=option_name,size_bytes 只列出名稱與位元組數,再交給 sort 依第二欄由小到大排序,最後幾行就是目前佔用最大的選項:
wp option list --autoload=on --fields=option_name,size_bytes | sort -n -k 2 | tailCode language: Bash (bash)
這份排行一樣只涵蓋 on 與 yes 兩種值、也不含暫存資料,拿來找大戶夠用。比起手動打開資料庫管理介面翻找,這個做法能直接放進定期巡檢的腳本裡,跟前面 Site Health 的門檻數字一起追蹤。
自動載入清單裡的正常、異常與殘骸三種訊號
查詢語法前面兩節都給過了,這裡要處理的是更實際的問題,清單撈出來,一堆看起來像亂碼的 option_name,要怎麼判斷哪些是正常、哪些是異常、哪些又是該清掉的殘骸。
第一個該認得的訊號是 _transient_ 或 _site_transient_ 開頭的選項。依 WordPress 開發者文件裡 set_transient() 的寫法,有設到期時間的暫存資料不會被自動載入,沒設到期時間的才會,如果在自動載入清單裡看到大量帶有 transient 字樣的資料,這件事本身就是異常訊號,代表某支外掛把原本該是暫時性的快取資料,存成了不會過期、每頁都載入的形式,值得優先往下查是哪支外掛做的。
第二類是 WordPress 核心自己就需要的選項,像 rewrite_rules、active_plugins,或跟排程有關的 cron 相關資料。這幾個名稱體積可能不小,但它們屬於核心運作必要的一部分,不是異常,不要看到體積大就直接刪掉或關閉自動載入,否則反而會讓網站的固定連結、外掛啟用清單或排程功能出問題。
第三類才是真正該清理的殘骸:某個看起來眼熟、像是外掛名稱縮寫的前綴,對照後台目前的已安裝外掛清單,卻完全找不到對應。Kinsta 對這種情況的建議做法,是先用選項名稱裡的關鍵字去比對主機上實際存在的外掛與主題目錄,找不到對應來源時,再改用搜尋引擎查這個選項名稱,通常能確認它原本屬於哪一支已經被移除的外掛。名稱對不上任何現存外掛的,多半就是前面提到的第二種成因造成的殘留,可以放進待清理的名單。
三類訊號分開看,就能清楚判讀:transient 大量出現代表外掛設定錯誤、核心必要選項屬於正常不用處理、查無對應的前綴才是真正的殘骸。這一步做完,手上就有一份確定可以動的名單,可以進到下一步決定怎麼處理。
調成不自動載入,還是直接刪除的判斷依據
上一節篩出來的名單,實際處理前有一件事務必先做,完整備份資料庫。不管接下來是要改欄位還是刪資料,這個動作都是直接動 wp_options 這張核心表,一旦改錯,輕則某支外掛失效,重則後台整個打不開,備份是唯一的後悔藥。用 WP-CLI 備份只要一行:
wp db export backup-before-autoload-cleanup.sqlCode language: Bash (bash)
沒有 WP-CLI 的環境,改用一般的 mysqldump 也可以:
mysqldump -u 資料庫帳號 -p 資料庫名稱 > backup.sqlCode language: Bash (bash)
備份做完,對照名單決定處置方式,大致分三種情況。第一種是外掛還在使用、只是這筆設定其實不需要每一頁都載入,這種情況資料要保留,只把自動載入狀態關掉。WP-CLI 有現成指令可以直接改:
wp option set-autoload abc_options noCode language: Bash (bash)
<autoload> 這個參數可以接受 on、off、yes、no 這幾種值,執行成功後會回傳一行確認訊息,說明這個選項的自動載入值已經更新。不想用 WP-CLI 的話,直接改資料庫欄位也可以,把 autoload 欄位改成新版的 off 即可,舊版 WordPress 也只把 yes 當成自動載入,不會因此出錯;只是直接改資料庫不會同步更新物件快取,有裝物件快取的站改完要清一次快取:
UPDATE wp_options
SET autoload = 'off'
WHERE option_name = 'abc_options';Code language: SQL (Structured Query Language) (sql)
第二種是外掛已經確定不再使用,對照過現存外掛清單也找不到任何對應,這種資料才適合直接刪除:
DELETE FROM wp_options
WHERE option_name = 'abc_options';Code language: SQL (Structured Query Language) (sql)
第三種是前面提到的核心必要選項,像 rewrite_rules、active_plugins 這類,不管體積多大都不要動,這一類唯一該做的事就是放著不管。三種處置對應的是三種不同的判斷,不是看到清單就一律關掉自動載入,也不是看到體積大就一律刪除,順序永遠是先判斷這筆資料屬於哪一種,再決定要不要動。

停用外掛前,先把它殘留的選項也一併清乾淨
前面幾節處理的都是事後補救,已經養大的 autoload 資料要回頭清理。但真正有效率的做法,是在停用或移除外掛的當下,就順手把它寫進 wp_options 的設定一併清乾淨,不要等到累積成一長串殘骸才回頭大海撈針。
不少外掛其實有提供解除安裝時清除自身資料的選項,通常在外掛自己的設定頁面裡,或是寫在它的說明文件裡。Kinsta 對這個習慣的提醒是,好的做法是先查看外掛開發者的文件,因為有些外掛確實提供清除殘留資料的選項;遇到已經移除、卻懷疑當初沒清乾淨的外掛,有時比較安全與簡單的做法,反而是重新安裝這支外掛、啟用它的自動清除選項,再依照正常流程移除,而不是自己手動去資料庫裡猜哪些欄位屬於它。
養成這個習慣以後,前面幾節教的排查方法,用途會從每次都要處理,變成定期確認沒有漏網之魚,兩者搭配起來,才是真正讓 autoload 資料不再無止盡累積的做法。
最新版 WordPress 核心會自動擋住過大的選項
前面幾節查資料庫、判斷、清理,聽起來都是站長自己得動手的事,但實際上 WordPress 核心本身近年已經內建了一道防線,只是多數舊教學,不分中英文,寫的都還是核心加這道防線之前的行為,沒有把它算進去。
WordPress 核心開發團隊在同一篇 Make WordPress Core 文章說明,當一個選項透過 add_option() 被新增,或透過 update_option() 被更新它的值時,WordPress 現在會在寫進資料庫之前,動態檢查這個值的大小,藉此決定要不要停用它的自動載入行為。具體的判斷條件是,對於沒有明確傳入 true 給 $autoload 參數的選項,只要它的值大於 150,000 位元組,文章裡簡稱 150k 位元組,核心就不會再把它設為自動載入,即使外掛開發者原本沒有特別交代這筆資料要不要自動載入。
這個門檻不是寫死不能調的,核心提供了一個叫 wp_max_autoloaded_option_size 的篩選器,可以用來調整這個判斷的大小門檻,預設值就是 150000。核心團隊的文件也特別提醒,調高這個數值並不建議,因為可能反而導致效能變差,等於是自己拆掉這道防線。
這道機制是核心內建的,不是靠外掛加上去的,而且舊版本那種只有 yes/no 兩種值的寫法完全相容,不會因此突然故障。但這不代表可以完全不管。舊外掛如果一直沒更新,或是明確要求某筆資料一定要自動載入,還是會照舊被載入;核心的自動判斷只是攔住開發者沒特別指定、資料又剛好過大的這種情況,是最後一道防線,不是萬用解方,前面幾節教的定期檢查跟手動判斷,還是省不掉。
把自動載入巡檢排進例行的外掛管理習慣
autoload 資料清乾淨一次,不代表往後就不會再養胖回去。真正讓效果維持住的,是把檢查排進日常的外掛管理習慣裡,而不是等到網站又變慢、又打不開才想起來要查。
第一個具體做法,是把總量查詢排進每次新裝外掛的例行動作,裝新外掛前先跑一次前面教的 SQL 查詢,記下當下的總位元組數,裝完外掛再跑一次,兩個數字一比對,差異多半就是這支新外掛造成的。這個做法比事後在幾百筆選項裡大海撈針、判斷哪支外掛該為異常增長負責有效率得多,而且是在問題還很小、還沒累積到影響效能的時候就抓到源頭。
第二件事跟前面提到的物件快取有關。裝了 Memcached 或 Redis 這類物件快取,確實能讓同一份自動載入資料在多次請求之間被重複使用,減緩即時感受到的效能傷害,但像 Memcached 這類物件快取本身對單一物件設有大小上限,前面提到 WP VIP 的 1MB 門檻就是實例。裝了物件快取只是延後你感受到問題,不是解決了問題,資料量還是會照樣往上疊,源頭沒清,遲早還是會撞到那個上限。
資料庫操作永遠先備份,這件事前面已經提過,這裡值得再說一次,巡檢養成習慣以後,真正需要動手改欄位、刪資料的次數會越來越少,但只要有動手的一天,備份這一步都不能省。把總量查詢、新裝外掛前後比對這兩件事排進固定的維運節奏裡,同時記得物件快取只是緩解、不是解方,autoload 資料就不容易再回到當初那個要靠健康檢查頁跳出重大問題,才讓人注意到的狀態。
wp_options 這張表本身不是問題,autoload 欄位也不是設計錯誤,問題出在沒有人定期回頭看這包資料養到多大。工具用不用得到都無所謂,真正決定網站快不快、穩不穩的,是有沒有人在它逼近警戒線之前,先打開後台或跑一行指令看一眼這個數字,這個習慣建立起來,遠比等到網站真的打不開才臨時抱佛腳,划算得多。
