資料庫是 Web 應用核心。PHP + MySQL 是經典組合,但許多開發者在資料庫設計、查詢、安全上踩坑。本文整理 11 大高頻錯誤,提供具體修正碼與最佳實務,適用 MySQL/MariaDB/Percona,亦可推廣至 PostgreSQL 等關聯式資料庫。
錯誤:預設建表用 MyISAM,不支援外鍵、交易、行級鎖,寫入鎖全表。
正確:一律用 InnoDB (MySQL 5.5+ 預設)。支援 ACID、行級鎖、外鍵、MVCC、崩潰恢復。
CREATE TABLE users (...) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
錯誤:mysql_connect、mysql_query、mysql_fetch_assoc (PHP 7.0 移除)。
正確:mysqli (面向物件/程序) 或 PDO (資料庫抽象)。
// PDO 推薦:支援多資料庫、預備語句、異常處理
$pdo = new PDO('mysql:host=localhost;dbname=app;charset=utf8mb4', $user, $pass, [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
PDO::ATTR_EMULATE_PREPARES => false, // 真實預備語句
]);
$stmt = $pdo->prepare('SELECT * FROM users WHERE email = ?');
$stmt->execute([$email]);
$user = $stmt->fetch();
錯誤:直接拼接變數 "SELECT * FROM users WHERE name='$name'"。
正確:永遠使用預備語句,參數綁定自動轉義。
// 錯誤
$sql = "SELECT * FROM users WHERE name='$_POST[name]'";
// 正確
$stmt = $pdo->prepare('SELECT * FROM users WHERE name = ?');
$stmt->execute([$_POST['name']]);
錯誤:預設 latin1、gbk、utf8 (僅支援 BMP,不支援 Emoji)。
正確:全鏈路 utf8mb4。
-- 資料庫/資料表/欄位
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
-- 連線
$pdo->exec("SET NAMES utf8mb4");
-- my.cnf
[client] default-character-set=utf8mb4
[mysql] default-character-set=utf8mb4
[mysqld] character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
錯誤:撈全表到 PHP 迴圈算平均、求和、去重、分頁。
正確:推給資料庫:AVG(), SUM(), COUNT(DISTINCT col), LIMIT/OFFSET, GROUP BY。
// 錯誤:撈 10 萬筆算平均
$rows = $pdo->query('SELECT price FROM products')->fetchAll();
$avg = array_sum(array_column($rows,'price'))/count($rows);
// 正確:一條 SQL
$avg = $pdo->query('SELECT AVG(price) FROM products')->fetchColumn();
錯誤:WHERE email = '...' 無索引,百萬筆全表掃描。
正確:
type (避免 ALL)、key、rows。slow_query_log=1, long_query_time=1,定期分析。| 錯誤 | 正確 | 理由 |
|---|---|---|
| 日期存 VARCHAR/INT | DATE / DATETIME / TIMESTAMP | 支援篩選、運算、索引、時區 | 金額存 FLOAT/DOUBLE | DECIMAL(10,2) | 避免浮點誤差 |
| 大文本存 TEXT 不加長度 | 視大小選 TINYTEXT/TEXT/MEDIUMTEXT/LONGTEXT | 儲存效率、排序限制 |
| 布林存 INT(1) | TINYINT(1) 或 BOOLEAN | 語意清晰 |
| JSON 存 TEXT | JSON 型別 (MySQL 5.7+) | 支援索引、路徑查詢、驗證 |
錯誤:SELECT * FROM users 傳輸不必要欄位、破壞覆蓋索引、增加網路/記憶體。
正確:明確列出欄位 SELECT id, name, email FROM users。
ANALYZE TABLE 更新統計;刪除未用索引 (DROP INDEX)。錯誤:從未備份、備份未驗證可還原、備份與主庫同機房。
正確:
mysqldump --single-transaction --routines --triggers 或 Percona XtraBackup (熱備份)。MySQL 非唯一選擇:
資料庫設計錯誤修正成本呈指數級增長:開發期 1×、測試期 10×、上線後 100×、資料遷移 1000×。先想清楚,再建表。