WordPress

WooCommerce效能優化:從前台到資料庫,抓出真正拖慢的瓶頸

行動網頁載入時間只要超過 3 秒,53%的使用者就會直接離開,這是 Google 在《The Need for Mobile Speed》報告裡算出的數字;把載入時間從 1 秒拉長到 3 秒,跳出機率還會再往上跳 32%,則來自 Google 與 SOASTA 合作的另一份研究。這兩個百分比,也是 WooCommerce 商店主最該放在心上的數字。你的商店如果在商品頁、購物車、結帳這幾步各多花零點幾秒,等於每一步都在把訪客往外推。WooCommerce 又剛好是把這個風險放到最大的地方,它比一般以內容取勝的網站多了商品目錄、購物車狀態、訂單資料庫,每一層都可能是拖慢速度的來源。

只是網站變慢這句話,對 WooCommerce 商店主來說常常是一個假議題,因為它其實包著好幾種完全不同的問題。前台商店頁載入得慢,跟後台訂單列表滑不動,成因幾乎不會是同一件事;就算同樣是前台慢,商品目錄的篩選頁跟結帳頁變慢的原因也常常兜不上。裝一套快取外掛能解決其中一種,另外幾種卻完全沒感覺,這也是為什麼不少店家該裝的外掛都裝了,網站還是慢。

先把問題分流,才知道要往哪裡查:前台的瓶頸多半靠快取就能處理,後台、資料庫層的瓶頸則要深入 WooCommerce 本身的架構才排得掉,兩者的成因完全不一樣。

前台慢與後台慢是兩種不同的問題

多數人講「WooCommerce 變慢」,腦子裡想的往往只有一種畫面,就是網頁轉圈圈轉很久。但實際上,前台商店頁、購物車與結帳、後台管理,這三個區塊各自的瓶頸完全不同,混在一起排查最容易白做工:快取外掛裝好了,後台管理還是卡;資料庫清過了,結帳頁一樣慢半拍。

要先分清楚變慢的是哪一段,而不是急著套解法。前台這端,先用 GTmetrix 或 PageSpeed Insights 分別測商品頁跟結帳頁的 TTFB(Time to First Byte,伺服器回應第一個位元組所花的時間);如果 TTFB 超過 500 毫秒,通常指向主機端或伺服器處理本身的瓶頸,不是前端資源(圖片、CSS、JS)的問題。接著打開瀏覽器內建的開發者工具,看 Network 面板的瀑布圖,找出哪一個請求把整個載入時間拖長,是某張圖片特別大,還是某支腳本拖住整條載入序列,瀑布圖看得一清二楚。

後台這端,工具換成 Query Monitor,這是一款免費外掛,能列出單一頁面載入時觸發的所有資料庫查詢、載入的腳本、發出的 HTTP API 呼叫,以及各自耗掉的時間,是後台排查的起點。裝上之後打開變慢的那個後台畫面,Query Monitor 的工具列會直接秀出這頁跑了幾支查詢、哪一支花最久,不必自己土法煉鋼猜。

前台慢用 GTmetrix、PageSpeed Insights 測 TTFB,後台慢改用 Query Monitor 查詢,兩種瓶頸成因不同要分開排查
WooCommerce 變慢先分流:前台瓶頸多半靠快取層處理,後台則要深入 WooCommerce 架構本身。

判斷後台是不是真的獨立出問題,有一個簡單的檢查,就是先看前台是不是也一樣慢。如果前台同樣有拖延,通常優先處理前台的瓶頸,會連帶釋放伺服器資源,後台反應也會跟著改善;只有前台正常、偏偏登入後台才慢,才代表問題真的出在後台這一側。

也要先認清楚一件事,前台頁面快取能覆蓋的範圍,只到商店首頁與商品頁這種內容對誰都一樣的頁面;購物車、結帳、我的帳號頁這幾個天生就不能被整頁快取,硬把它們塞進快取規則,反而可能讓不同訪客看到彼此的購物車內容。

這個分流框架也不是憑空訂出來的順序。WooCommerce 官方的疑難排解文件列出的診斷順序是:先確認快取與 CDN 運作正常,再檢查主機方案本身的影響、圖片與程式碼是否經過壓縮,接著確認記憶體限制是否足夠,最後才是逐一停用外掛排查、換回預設佈景主題。這份官方文件本身沒有再往資料庫層走,但快取與外掛這兩層,多數通用 WordPress 效能文都講得夠多,真正的資料庫層瓶頸,才是 WooCommerce 特有、卻最常被忽略的部分。

商品目錄擴大後,篩選與排序反應變慢

商品數一多,前台的篩選頁跟排序頁開始變慢,這是 WooCommerce 特有的一種瓶頸,而且跟快取完全無關。快取外掛能幫的是同一個頁面重複出現時直接讀現成的結果,但篩選頁的組合五花八門,顧客可能選尺寸 M 加顏色藍,也可能選庫存有貨加價格排序,排列組合太多,快取根本存不了那麼多版本。真正的瓶頸是查詢本身,裝再多前台快取外掛都救不了。

WooCommerce 用一張獨立的資料表 wc_product_attributes_lookup 來支援依規格、庫存狀態篩選商品,這張表的用途是讓系統可以直接查這張精簡過的表,而不必掃過整個商品資料表去比對每一件商品的規格。問題出在這張表要維護,商品數與規格組合一多,重建這張表的過程本身就會拖慢速度,篩選跟排序頁的反應也跟著變差。

WooCommerce 官方也承認,舊版的重建機制在商品變體(variation)數量龐大的商店上,效能表現不理想。原本的做法是逐一呼叫 wc_get_product 收集每件商品的資料,商品一多,這個逐筆處理的方式就會拖很久。WooCommerce 9.1 版起,官方把重建路徑改成以直接資料庫查詢為主,把處理時間從原本的數秒壓到毫秒等級,同時把預設批次量從 10 筆一次調高到 100 筆,減少了整個重建過程需要排程的動作數量。

如果你的商店還沒用上這個優化,可以到 WooCommerce 的設定裡,產品→進階頁面,勾選「最佳化更新」這個開關。要注意的是,這個開關只有在商品資料仍儲存在 WordPress 通用的文章資料表時才會生效,如果你的商店裝了某些擴充套件、把商品資料改存到別的資料類別,這個設定就不會套用。開了之後,背景重建也改成用批次處理,不必等系統排程慢慢跑完,也可以直接下指令 wp wc palt regenerate,手動針對單一商品或整個商店重建這張查詢表。

判斷是不是這個問題也不難:如果篩選頁、排序頁比一般商品頁明顯慢上一截,而且商品數量或規格組合本來就多,這張查詢表的重建效率就是第一個該檢查的地方,而不是先去找快取設定有沒有錯。

購物車與結帳頁面天生無法被整頁快取

很多通用 WordPress 效能文,把裝好一套快取外掛講得像萬靈丹,只要裝了、設定調對,全站就會變快。這句話對商店首頁、商品頁大致成立,但套到購物車、結帳、我的帳號頁,就完全不是這麼一回事,這幾頁本質上無法被整頁快取,不是你設定沒調好,是架構設計上的必然。

原因在於 WooCommerce 判斷購物車狀態,靠的是幾個特定的 cookie,例如 wp_woocommerce_session 跟 woocommerce_cart_hash。只要瀏覽器帶著這些 cookie 送出請求,不管是伺服器端的頁面快取,還是 CDN 的邊緣快取(edge cache),都必須把這個請求排除在快取範圍之外,直接放行給系統即時處理。理由也很直覺,購物車內容因人而異,如果把某一位顧客的購物車頁面存成快取,拿去回應下一個訪客,對方就會看到別人的購物車,這是絕對不能發生的事。

Cloudflare 官方部落格說明,他們的 Automatic Platform Optimization(自動平台優化,簡稱 APO)在做 HTML 邊緣快取時,機制上會排除帶有 WordPress 與 WooCommerce 特定 cookie 的請求。當訪客把商品加進購物車,系統設定 woocommerce_items_in_cart 這類 cookie,APO 就會直接略過快取,避免把這位訪客當下客製化的內容,快取後端給下一個訪客看到。DebugBear 的技術分析補充了更完整的清單:只要偵測到 wordpress_logged_in_[hash]、wp_woocommerce_session、woocommerce_cart_hash 這幾種 cookie 其中之一,整頁快取就會被停用,而這正是電商網站跟一般部落格或形象網站,效能表現落差最主要的來源之一。

理解這個機制之後,優化這幾頁的方向就要跟著調整。不是想辦法讓它也被快取,那既做不到、硬做還有資安風險;真正該做的是減少這幾頁本身要即時運算的份量,讓每一次真正跑動態邏輯的請求變輕、變快。購物車片段 AJAX 跟物件快取這兩個機制,都是針對這幾個沒辦法靠快取偷懶的頁面設計的,想讓它們本身的運算變輕、變快。

購物車沒有異動時,仍會觸發背景更新請求

WooCommerce 有一個立意良好、卻常常拖累效能的機制,叫做購物車片段(cart fragments)。它靠一支叫 get_refreshed_fragments 的 AJAX 請求,在購物車內容有變動時,不用重新整理整個頁面,就能即時更新畫面右上角的購物車圖示、數量跟金額。問題是,這支請求不是只在購物車真的有變動時才觸發,它常常在使用者根本沒有動過購物車的頁面上,也照樣打一次,例如首頁、商品列表頁,每次載入都白白多一個沒有必要的請求。

這跟外掛裝太多、腳本太多是不同層次的問題。一般效能問題可以靠停用不必要的外掛解決,但購物車片段是 WooCommerce 核心內建的行為,不管你裝了多乾淨的一套外掛組合,只要開著購物車功能,這支請求就在那裡。要辨認它也不難,打開 GTmetrix 或瀏覽器 DevTools 的 Network 面板,瀑布圖裡找網址帶著?wc-ajax=get_refreshed_fragments 特徵的那一筆,就是它。

國際效能外掛 Perfmatters 的官方文件測試指出,在小型測試網站上,這支請求的耗時已經超過同一頁面其他任何請求;官方原文寫得更直接,在大型網站上,他們看過這個請求造成長達 10 秒的延遲。對共用主機上的大型商店來說,這種等級的拖延足以拖垮整頁的載入體驗。

get_refreshed_fragments 在購物車沒有異動的頁面也每次載入照打一次,大型網站上最長可造成 10 秒延遲
購物車片段的 get_refreshed_fragments,購物車沒變動時也每次載入照打,大型網站上最長延遲 10 秒(資料來源:Perfmatters)。

停用它有一個相對安全的做法,就是先檢查 woocommerce_cart_hash 這個 cookie 存不存在。這個 cookie 不存在,代表購物車目前是空的,此時就可以安全地不觸發這支請求,不會影響到任何實際功能;等到真的有商品被加進購物車,cookie 出現了,請求才恢復運作。這個判斷方式比整站直接關掉這個機制更保守,也更不容易誤傷。

有一件事關掉這支請求之後一定要記得處理,到 WooCommerce 的設定裡,產品→顯示,把「加入購物車後導向購物車頁」這個選項打開。原因是購物車片段原本負責的其中一項工作,就是讓使用者按下加入購物車後,畫面上的購物車數字能立刻跟著變動;停用它之後,如果沒有搭配導向購物車頁,使用者按下按鈕卻看不到任何畫面上的變化,很容易誤以為根本沒有加入成功,反而製造出新的困惑。

訂單頁面的更新頻率拖慢後台反應

WordPress 核心有一套叫 Heartbeat API 的機制,讓瀏覽器每隔 15 到 120 秒,對 admin-ajax.php 送出一次背景請求,近乎即時地讓前後端保持同步。它的用途包括自動儲存草稿、鎖定正在編輯的文章(避免兩個人同時改同一篇稿子互相覆蓋)、登入逾時前提醒使用者。對一般的 WordPress 後台來說,這個機制的影響通常有限,大多數畫面的預設頻率是 60 秒一次,只有文章編輯畫面會提高到 15 秒一次,負擔並不重。

但 WooCommerce 的訂單管理頁,會讓每一次心跳額外多背一次負擔。訂單頁在每次心跳請求裡,會附加訂單通知的檢查,等於每隔一段時間就要多跑一次跟訂單相關的查詢。訂單量不多的時候感覺不出來,訂單量一旦成長,這個背景噪音疊加起來,就會變成看得出來的卡頓,尤其是同時開著訂單列表頁、又有其他人在後台操作的時候特別明顯。

WordPress Heartbeat 每 15 到 120 秒輪詢 admin-ajax.php,WooCommerce 訂單頁還替每一次心跳附加訂單通知檢查
Heartbeat 心跳本身負擔不重,但訂單管理頁替每一次心跳多背一次訂單查詢,訂單量一大就看得出卡頓。

要點明的是,這不是外掛裝太多的問題,是 Heartbeat 機制本身,加上 WooCommerce 在訂單頁疊加的效應共同造成的。WordPress 官方開發者文件說明,Heartbeat 的運作方式是頁面載入後,前端程式碼設定一個 15 到 120 秒的輪詢間隔,每次觸發都透過 admin-ajax.php 送出請求並等待伺服器回應,伺服器再依附加的資料回傳對應內容,這個機制本身的設計目的就是自動儲存、文章鎖定、登入逾時提醒這類近乎即時的同步。

處理這個問題的原則是按畫面調整,而不是整站直接關掉。文章編輯畫面的自動儲存與鎖定編輯功能,通常你會想保留,真正該調整的是訂單列表頁或儀表板這類心跳負擔重、卻不需要那麼即時的畫面,可以拉長頻率,或針對特定畫面停用。完全關閉 Heartbeat 之前,務必先確認有沒有依賴它的外掛,例如某些即時訂單提醒外掛,就是靠這個機制推送通知,整站關掉會讓這類功能直接失效,反而製造新的問題。

切換主題會啟動背景縮圖重生工作

WooCommerce 從 3.3 版開始,只要你在佈景主題的自訂器裡調整商品圖片的尺寸或裁切比例,或者直接換了一套佈景主題,系統就會自動排一個背景工作,把全部商品圖重新產生一次縮圖。這個機制的立意是省掉你另外裝外掛手動重跑縮圖的麻煩,圖片尺寸一改,新縮圖就自動生成好,不用自己再跑一次。

問題出在觸發的時間點沒得選,對商品圖片數量多的商店來說,一次觸發的當下,背景處理佇列會瞬間塞進一整批任務。這種商店常常同時裝了 CDN 外掛,而多數 CDN 外掛的做法,是監聽核心產生縮圖的那個 hook,縮圖一產生完成就立刻上傳到第三方服務。等於每一張縮圖除了本身的重生時間,還要再疊加一段上傳到 CDN 的時間,兩個負擔加在一起,那段時間站台整體反應就會明顯變慢。不少店家搞不清楚狀況,只知道換了個主題,全站突然變慢,卻不知道背後在跑的其實是這個背景工作。

要確認觸發時機,其實只有兩種:在自訂器裡發布跟圖片相關的設定,或者切換佈景主題,除此之外不會憑空啟動。如果想知道背景重生跑到哪裡了,WooCommerce 的狀態頁裡有記錄檔可查,到 WooCommerce→狀態→記錄檔,選 wc-background-regeneration 這個記錄檔,就能看到處理進度。有一種情況這個功能會直接失效,如果站台掛在 BasicAuth 驗證後面,例如某些測試站或還沒對外公開的預發布站,背景處理跟非同步請求需要額外帶上驗證資訊才能通過,沒有處理的話這個功能等於形同虛設。

如果你想完全掌控重生的時機,例如排在離峰時段手動處理,而不是被系統自動觸發,可以用 woocommerce_background_image_regeneration 這個 filter 把背景重生整個關掉,改用其他重生外掛,自己選時間手動執行。這樣至少可以避開跟 CDN 上傳疊加在一起,拖慢尖峰時段流量的情況。

舊式資料表和 HPOS 的訂單查詢速度差距

大部分通用 WordPress 效能文完全不會提到訂單資料儲存架構本身的差異,但這正是 WooCommerce 最容易被忽略的效能戰場。WooCommerce 8.2 版之前,每一筆訂單資料一律借用 WordPress 通用的文章與文章詮釋資料表格存放,一張訂單被拆成一筆文章紀錄,加上數十筆詮釋資料,帳單地址、收件地址、金流方式、訂單狀態、各種外掛附加的自訂欄位,全部塞進這張什麼都放的通用表裡,單一筆訂單大約會產生 40 筆資料列。訂單量一多,這兩張表就會被撐得肥大,後台篩選訂單、建立新訂單這些日常操作,都會跟著變慢。

高效能訂單儲存(High-Performance Order Storage,簡稱 HPOS)改變了這個架構,不再借用通用的文章表,而是改用 4 張專屬於訂單的資料表:訂單主表存放核心資訊,訂單地址表專門放帳單與收件地址,訂單營運資料表放金流、狀態這類營運相關欄位,訂單詮釋資料表放各外掛的自訂欄位。同樣一張訂單,在這套架構下大約只需要 5 筆資料列,比原本的 40 筆少了一大截。

效能落差官方給出的數字非常具體:訂單建立速度最高快 5 倍,結帳流程最高快 1.5 倍,而在營運面,後台找到一筆訂單的速度最高可以快 40 倍。這幾個數字的意義不太一樣,訂單建立跟結帳的提速,顧客在前台感受得到;找訂單這個 40 倍的提速,則是客服跟營運人員每天在後台重複做的動作,對訂單量大的商店,這一項帶來的體感差異反而最明顯。

HPOS 用 4 張專屬訂單表把單一訂單從約 40 筆資料列降到約 5 筆,訂單建立、結帳、找訂單分別最高快 5、1.5、40 倍
改用 HPOS 後單一訂單的資料列從約 40 筆降到約 5 筆,後台找訂單最高快 40 倍(資料來源:WooCommerce)。

WooCommerce 8.2 版於 2023 年 10 月推出,自此之後,新安裝的商店預設就是用 HPOS 架構;但如果你的商店是在這之前就建立的,並不會自動切換,得自己到 WooCommerce 的設定裡,進階→功能頁面手動啟用。切換之前有一個步驟不能跳過,就是先勾選「相容模式」,讓舊的資料表跟新的資料表先同步一段時間,資料在兩邊都寫得到,才能真正切到以 HPOS 為主要資料來源。同時也要確認,商店目前使用中的所有擴充套件都已經標示相容 HPOS,如果有任何一個擴充套件不相容,切換的選項會直接被鎖住,得先處理好相容性問題才能繼續。

好消息是這個切換是可逆的。在你正式關閉相容模式之前,隨時都能切回舊架構,不會有資料回不去的風險。不過也正因為可逆,不少商店切換過去之後,長期讓相容模式一直開著,沒有進到下一步正式關閉,等於資料同時寫進新舊兩套表,實際上還沒有真正拿到 HPOS 帶來的效能與資料量優勢。

背景工作和暫存資料在資料庫裡持續累積

前一節談的是訂單資料表本身的架構問題,就算已經切到 HPOS,還有另一群東西,跟訂單資料表無關,卻同樣會撐大資料庫、拖慢反應,而且是持續在背景累積,不會因為你切換了訂單架構就自動消失。已經做完的背景工作,預設清理常追不上它累積的速度;規格組合多的商品,暫存資料的量也常常遠超過表面上看到的商品數字。

已完成的背景工作紀錄容易越積越多

WooCommerce 用一套叫 Action Scheduler 的佇列系統,處理各式各樣的背景工作:訂閱續訂、webhook 通知、通知信、還有各種排程任務,都是靠它在背景默默執行。它的運作方式是批次處理,官方預設一批處理 25 筆動作,同時間預設只跑 1 批(可透過 filter 調高並行批次數),靠掛載在 WP-Cron 上的 action_scheduler_run_queue 這個 hook 來觸發運作。

問題是,這套系統的自動清理有門檻:已完成、已取消的紀錄,預設要超過 31 天才會被排進每天固定跑一次的清理工作,失敗的動作則要保留長達 3 個月才會被清掉,而這個每日清理工作本身一樣掛在 WP-Cron 上觸發。也就是說,只要站台流量太小、WP-Cron 沒被穩定觸發,或是背景工作本身產生的速度就快,30 天的門檻還沒到、紀錄就已經比清得掉的還多,存放這些紀錄的資料表照樣會慢慢膨脹成一張大表。這張表一旦肥大,拖慢的不只是跟訂單相關的頁面,連跟訂單完全無關的頁面,也會因為資料庫整體反應變慢而跟著被拖累。

檢查這張表的狀況時,有一個訊號要特別留意,就是逾期未執行(past-due,超過一天以上還沒被執行)的動作數量。官方文件指出,偶爾出現逾期未執行的動作屬於正常現象,畢竟 WP-Cron 本身依賴訪客造訪網站觸發,不是絕對準時的排程系統;但如果逾期超過一天以上的動作大量堆積,就代表站台某個環節出了問題,常見的原因是主機端限制了 WP-Cron 的執行頻率,或者某個外掛擋住整條佇列,讓後面排隊的動作跟著動彈不得。這種情況不是單純清理資料庫就能解決,得先找出堵住的環節。

Action Scheduler 每批處理 25 筆動作、同時只跑 1 批,已完成的紀錄 31 天才清、常追不上,資料表持續膨脹
Action Scheduler 一批處理 25 筆動作,做完的紀錄要 31 天才清、常追不上累積速度;逾期未執行的動作大量堆積就是站台出問題的訊號。

真的要清理已經完成的紀錄之前,務必先備份,也要仔細確認沒有誤刪還在排程中、還沒執行的動作。清理的對象只限於已完成這個狀態,把還沒跑完的工作一起清掉,反而會製造新的問題,例如訂閱續訂該執行卻沒執行。

規格組合越多,商品的暫存資料越龐大

可變商品(variable product)是另一個容易被低估的資料膨脹來源。一個商品只要有多種規格組合,例如同時有多種尺寸又有多種顏色,後台其實是把每一種組合都存成一個獨立的變體(variation),每個變體各自帶著一整組詮釋資料:價格、庫存狀態、貨號、重量、尺寸,一應俱全,不是共用同一份,而是每個組合都各自存一份。

這代表商品數字本身會低估實際的資料量。舉例來說,一件商品如果有 5 種尺寸乘上 8 種顏色的組合,會產生 40 個變體,每一個變體都各自帶著一整組詮釋資料列。乍看商品清單只有寥寥幾項,後台實際存放的資料量,卻遠遠超過商品數字表面上看起來的規模,這種落差在商品數不多、但規格組合設計得很複雜的商店特別容易出現。

可以清理的部分很有限,只有已經被刪除的商品留下的孤兒詮釋資料能安全清掉;正在使用中的變體資料,是活的商品資料,不能當成垃圾清除。真正該檢視的,其實是規格組合的設計本身。如果某個商品開出了數百種變體組合,但實際上真正有人買的只是其中一小部分,這是商品規格設計的問題,不是資料庫的問題,該處理的方向是精簡規格選項,把很少人選的組合拿掉,而不是回頭在資料庫裡找東西清。

沒有物件快取,購物車與庫存查詢反覆重新執行

前面幾節談到的購物車 session、庫存數量、運費試算,這些內容都不是靜態的,沒辦法用頁面快取解決,畢竟每個人的購物車內容都不一樣,運費也隨著收件地址跟購物車重量隨時變動。但這不代表這幾個地方就沒有加速的空間,真正能派上用場的是物件快取(Object Cache),搭配 Redis 或 Memcached 這類記憶體資料庫,把常被重複查詢的資料暫存在記憶體裡,下一次遇到同樣的查詢,就不必再回頭問一次資料庫。這是購物車、結帳這幾個注定不能被頁面快取的頁面,真正能提速的方法。

WooCommerce 會把商品資料、庫存數量、運費試算結果,存成一種叫暫存資料(transient)的東西,而這些暫存資料要真正發揮效果,存取路徑得經過物件快取這一層。沒有裝物件快取外掛的情況下,WordPress 內建的物件快取只在單次頁面請求的生命週期內有效,請求一結束,快取就跟著清空,下一個訪客送出的請求,系統還是得重新查一次資料庫,完全沒有真正省到重複查詢的成本。

裝上 Redis 或 Memcached 之後,情況就不一樣了。這種常駐型的物件快取(persistent object cache),可以讓快取資料跨越單次請求持續存在,不會請求一結束就消失。ScalaHosting 與 Pressidium 這類國際主機與技術服務商的官方部落格說明,這類物件快取介於 WordPress 與 MySQL 資料庫之間,把查詢結果直接存在記憶體裡,之後同樣的查詢就能從記憶體讀取,速度是微秒等級,而不必每一次都重新查資料庫。開了持久化物件快取之後,每一次購物車更新、商品瀏覽、結帳步驟觸發的多筆查詢,都能直接從記憶體讀取結果。

要留意的是主機環境本身要支援讓 Redis 這類服務持續常駐運行,不是每一種共用主機方案都提供這個條件。這也是為什麼加裝物件快取常常跟換一個主機方案一起被拿出來討論,因為前者往往得先滿足後者的條件才能真正裝得上去。WooCommerce 官方的快取說明文件也建議,搭配 Redis 或 Memcached 使用持久化的物件快取,而不是只依賴頁面快取,兩者處理的其實是不同層次的問題:頁面快取處理的是能被整頁存起來的內容,物件快取處理的則是像購物車、結帳這種天生不能整頁存、卻仍然值得省下重複查詢成本的地方。

訂單量成長後,同一批瓶頸會用更大規模出現

前面談到的每一種瓶頸,商品規格查詢表、Action Scheduler 佇列、購物車片段 AJAX、HPOS,幾乎都有一個共通的性質,都是隨規模才會顯現的問題。同一套設定,商店在訂單量小的時候完全沒有感覺,訂單量成長到一定規模,原本處理過的環節會重新變成瓶頸,而且往往是同一個地方,只是這次用更大的量再撐一次。

Action Scheduler 佇列的大小、已完成動作的累積數量,會隨著訂單、訂閱、webhook 的數量持續成長。就算當初已經清理過一次,一段時間之後,同一張表可能又慢慢肥大回去,這種清理其實是要持續進行的工作,不是清一次就一勞永逸。同樣的道理也適用在 HPOS 上,遷移完成之後,如果一直保留著相容模式,舊表跟新表會同時寫入資料,等於完全沒有省到資料量,也沒有真正拿到 HPOS 帶來的效能優勢,得確認狀況穩定之後,手動把相容模式關掉,才算真正切換完成。

商品規格組合、變體數量,也會隨著新商品持續上架而增加。原本重建速度沒問題的商品規格查詢表,重建所需的時間會隨著商品數增加而拉長,今天沒問題不代表半年後同樣沒問題。要看出瓶頸有沒有捲土重來,最直接的地方是 WooCommerce 的狀態頁裡的排程動作(Scheduled Actions)畫面,定期看一下有沒有大量堆積、或者逾期未執行的動作,這是判斷同一個問題是不是又回來了最快的方式,比等到顧客反映網站變慢才回頭查,能提早抓到問題。

WooCommerce 的效能問題,很少是單一原因造成的,通常是好幾層瓶頸疊在一起才讓人覺得網站慢。搞懂前台快取處理得到哪裡、處理不到哪裡,分清楚是資料庫層的架構問題還是背景工作的累積問題,診斷起來才不會滿頭包地亂試一通。多數環節一開始都不明顯,卻會隨著商店規模成長,回頭用更大的量再考驗一次系統;把該檢查的地方養成定期回頭看一次的習慣,遠比等顧客抱怨網站變慢才臨時補救,來得從容也踏實得多。

常見問答

本區問答由 AI 依文章內容自動整理,僅供快速參考,正式內容仍以全文為準。

WooCommerce 網站後台變慢要用什麼工具排查?

後台排查建議用 Query Monitor 這款免費外掛,它能列出單一頁面載入時觸發的所有資料庫查詢、腳本與 HTTP API 呼叫,以及各自耗掉的時間,打開變慢的畫面就能直接看出哪一支查詢拖最久。

WooCommerce 購物車片段要怎麼關閉?

可以先檢查 woocommerce_cart_hash 這個 cookie 存不存在,不存在代表購物車是空的,此時安全地不觸發這支請求;關閉後要記得到產品設定把「加入購物車後導向購物車頁」打開,避免顧客看不到購物車已更新的畫面。

WooCommerce 訂單頁為什麼比後台其他頁面卡?

因為訂單頁在 WordPress 的 Heartbeat 心跳機制上,每次心跳都額外附加一次訂單通知檢查,訂單量一旦成長,這些背景查詢疊加起來就會變成看得出來的卡頓,處理方式是拉長訂單頁的心跳頻率,而不是整站關掉。

WooCommerce 要怎麼啟用 HPOS 訂單儲存?

到 WooCommerce 設定的進階>功能頁面手動開啟,切換前要先勾選「相容模式」讓新舊資料表同步一段時間,也要確認所有擴充套件都已標示相容 HPOS,任何一個不相容都會讓切換選項被鎖住。

WooCommerce 網站資料庫為什麼會越用越肥大?

常見原因是 Action Scheduler 這套背景工作佇列,已經處理完成的紀錄雖然預設 31 天後會自動清理,但流量小或背景工作產生太快時,清理常追不上累積速度,存放紀錄的資料表就會慢慢膨脹,連跟訂單無關的頁面也會被拖累,清理前務必先備份並確認沒有誤刪還沒執行的動作。

資料來源
  1. The Need for Mobile Speed (2016) — Google
  2. Find Out How You Stack Up to New Industry Benchmarks for Mobile Page Speed(Google/SOASTA Research, 2017) — Google
  3. Troubleshooting a slow site — WooCommerce
  4. An optimization for the product attributes lookup table is coming — WooCommerce
  5. Introducing Automatic Platform Optimization, starting with WordPress — Cloudflare
  6. WooCommerce Performance Optimization: How To Fix a Slow Online Store — DebugBear
  7. Disable WooCommerce cart fragments (wc-ajax=get_refreshed_fragments) — Perfmatters
  8. Heartbeat API — WordPress
  9. Thumbnail Image Regeneration in 3.3 — WooCommerce
  10. Platform Upgrade: High-Performance Order Storage for WooCommerce — WooCommerce
  11. WordPress Background Processing at Scale - Action Scheduler Job Queue — Action Scheduler
  12. Scheduled Action Errors — WooCommerce
  13. Redis Cache: Guide to High-Performance Caching — ScalaHosting
  14. WordPress Object Caching: Redis, Memcached and native APIs — Pressidium