PHP 擁有極佳的開發效率,但高流量、大資料量場景下效能調優至關重要。本文系統整理程式碼層面微優化、架構層面宏優化、快取策略、資料庫優化、部署調校等完整知識體系。
<?php
// ✅ 好:前置遞增、避免重複計算
for ($i = 0, $len = count($arr); $i < $len; ++$i) { ... }
// ❌ 差:後置遞增、每次迴圈呼叫 count()
for ($i = 0; $i < count($arr); $i++) { ... }
// ✅ 好:foreach 遍歷陣列(PHP 7+ 內部優化極佳)
foreach ($arr as $key => $val) { ... }
// ✅ 好:單引號字串(無變數解析,略快)
echo '靜態字串';
$str = 'Hello ' . $name . '!'; // 串接優於雙引號解析
// ✅ 好:盡用內建函式(C 實作,極快)
$sum = array_sum($arr); // 優於迴圈累加
$max = max($arr);
$filtered = array_filter($arr, fn($v) => $v > 10);
$mapped = array_map('trim', $arr);
| 殺手 | 影響 | 替代方案 |
|---|---|---|
| 在迴圈中 include/require | 重複編譯、IO | 自動載入、預先載入 |
| 頻繁存取 $_SERVER/$_GET 等超全域 | 陣列查找開銷 | 開頭指派給區域變數 |
| 錯誤抑制 @ | 極大效能懲罰 | 正確錯誤處理、isset() 檢查 |
| 大字串用 . 串接(迴圈中) | 記憶體重新分配、複製 | 陣列收集最後 implode()、或用輸出緩衝 |
| preg_* 正則濫用 | 編譯、匹配慢 | 簡單字串操作用 strpos/substr/str_replace |
| 未釋放大型資源 | 記憶體洩漏 | unset()、迭代器模式、生成器 yield |
; php.ini / .user.ini
opcache.enable=1
opcache.enable_cli=1
opcache.memory_consumption=256 ; MB,視專案大小調整
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=20000 ; 超過專案 PHP 檔案數
opcache.revalidate_freq=0 ; 0=每次檢查(開發),生產設 60 或更高
opcache.fast_shutdown=1
opcache.save_comments=1 ; 註解保留(註解路由、屬性需此項)
; Nginx gzip
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
gzip_comp_level 6;
; Apache mod_deflate
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css application/javascript application/json
; PHP 端輸出壓縮(若前端無代理)
ini_set('zlib.output_compression', 'On');
ini_set('zlib.output_compression_level', 6);
Cache-Control: public, max-age=31536000, immutable,檔名加入 hash 版本; 高併發改用 Redis
session.save_handler = redis
session.save_path = "tcp://127.0.0.1:6379?auth=pass&database=0&prefix=sess:"
; 或資料庫(參考 MySQL Session 文章)
// 生產者:推送任務
$redis->lPush('queue:email', json_encode(['to' => 'a@b.com', 'subject' => '歡迎', 'template' => 'welcome']));
// 消費者:Supervisor 管理多進程 Worker
while (true) {
$job = $redis->brPop('queue:email', 5); // 阻塞等待
if ($job) {
$data = json_decode($job[1], true);
sendEmail($data);
}
}
-- ❌ 差:深分頁掃描大量行
SELECT * FROM articles ORDER BY id DESC LIMIT 100000, 20;
-- ✅ 好:延遲關聯 / 游標分頁
SELECT a.* FROM articles a
JOIN (SELECT id FROM articles ORDER BY id DESC LIMIT 100000, 20) b USING (id);
-- ✅ 更好:Keyset 分頁(需唯一排序鍵)
SELECT * FROM articles WHERE id < 12345 ORDER BY id DESC LIMIT 20;
| 層級 | 技術 | TTL | 適用資料 | 一致性 |
|---|---|---|---|---|
| 瀏覽器 | HTTP Cache / ETag / Cache-Control | 靜態 1年、動態 0-60s | 靜態資源、API 回應 | 強/弱 |
| CDN/邊緣 | Varnish / Nginx fastcgi_cache / Cloudflare | 1m-1h | 全頁面、片段、API | 最終一致 |
| 應用層 | Redis / Memcached / APCu | 依業務 | 熱點資料、Session、Token、計數器 | 主動失效 |
| 資料庫 | Query Cache (MySQL 5.7-) / Buffer Pool | - | 熱點查詢結果 | 強 |
// Cache-Aside (旁路快取) - 最常用
function getUser(int $id): array
{
$key = "user:$id";
if ($data = $redis->get($key)) return json_decode($data, true);
$data = $db->query("SELECT * FROM users WHERE id=?", [$id])->fetch();
if ($data) $redis->setex($key, 3600, json_encode($data));
return $data;
}
function updateUser(int $id, array $data): bool
{
$ok = $db->update('users', $data, ['id' => $id]);
if ($ok) $redis->del("user:$id"); // 刪除快取,下次讀取重建
return $ok;
}
// Write-Through / Write-Behind 視一致性需求選擇
# PHP-FPM (www.conf)
pm = dynamic
pm.max_children = 200 ; 視記憶體:總記憶體 / 單進程記憶體
pm.start_servers = 20
pm.min_spare_servers = 10
pm.max_spare_servers = 50
pm.max_requests = 1000 ; 回收防記憶體洩漏
request_terminate_timeout = 60s
rlimit_files = 65535
# Nginx
worker_processes auto;
worker_rlimit_nofile 65535;
events { worker_connections 65535; multi_accept on; }
open_file_cache max=10000 inactive=30s;
sendfile on; tcp_nopush on; tcp_nodelay on;
PHP 效能優化是系統工程:程式碼微優化 → OPcache → 架構解耦(快取、佇列、非同步) → 資料庫索引/分頁/分庫 → 壓縮/CDN/HTTP2 → 監控閉環。無銀彈,需根據實際瓶頸(CPU、IO、鎖、網路)針對性調優,並建立效能基準測試與回歸機制。