MySQL 在默認配置下有許多「反直覺」行為,稍不留神就會導致數據不一致、查詢結果錯誤、索引失效。本文梳理開發與運維中最高頻的 5 大陷阱,附帶原理解析與最佳實踐。
utf8_general_ci(_ci = case insensitive),故 'a' = 'A' 為真。-- ① 列級:定義時指定 _cs 或 _bin
CREATE TABLE t (name VARCHAR(50) COLLATE utf8_bin);
-- ② 查詢級:COLLATE 子句
SELECT * FROM t WHERE name COLLATE utf8_bin = 'Abc';
-- ③ 會話級:設置連接排序規則
SET SESSION collation_connection = 'utf8_bin';
建議:表/庫名統一小寫(lower_case_table_names=1 強制轉小寫存儲),列數據按業務需求選擇 _bin(精確匹配、索引友好)或 _ci(模糊搜索)。
INSERT INTO users (phone) VALUES (NULL); -- 未知、不適用、尚未錄入
INSERT INTO users (phone) VALUES (''); -- 已知無電話、主動留空
NULL + 1 = NULL、NULL = NULL → NULL (非 TRUE)、NULL <> 'a' → NULL。WHERE phone IS NULL、WHERE phone IS NOT NULL。COUNT(phone) 不計 NULL 行;COUNT(*) 計總行數。IFNULL(col, 'N/A') / COALESCE(col1, col2, 'N/A') 用於顯示默認值。NOT NULL,則不可插入 NULL,且優化器可更激進優化(如 ref 訪問)。-- 字符排序按「權重」而非碼點
ORDER BY name -- 'A'='a' < 'B'='b' ... 但 'é' 與 'e' 權重可能相同
-- 穩定排序需顯式二級鍵
ORDER BY name COLLATE utf8_bin, id
GROUP BY 默認按分組列排序(MySQL 5.7+ 可用 ORDER BY NULL 禁止),DISTINCT 同理。
-- 文本文件中 \N 會被解析為 NULL
LOAD DATA INFILE 'data.txt' INTO TABLE t FIELDS TERMINATED BY '\t';
-- 若需導入空字符串,文件留空字段即可
| 列類型 | 插入 NULL 的實際行為 |
|---|---|
TIMESTAMP | 自動填充當前時間戳(首個 TIMESTAMP 列) |
AUTO_INCREMENT | 自動填充下一個自增值 |
DEFAULT CURRENT_TIMESTAMP (DATETIME/TIMESTAMP) | 填充當前時間 |
| 場景 | 錯誤寫法 | 正確寫法 |
|---|---|---|
| 判斷是否為 NULL | WHERE col = NULL | WHERE col IS NULL |
| 判斷非 NULL | WHERE col != NULL | WHERE col IS NOT NULL |
| 空值轉默認顯示 | SELECT col | SELECT COALESCE(col, '默認值') |
| 大小寫精確匹配 | WHERE name = 'Abc' (ci) | WHERE name COLLATE utf8_bin = 'Abc' |
| 計數含 NULL 行 | COUNT(col) | COUNT(*) |
MySQL 的這些「特性」實為 SQL 標準與實現妥協的產物。養成顯式聲明排序規則、用 IS NULL 判斷空值、區分 NULL 與空串、理解特殊列隱式行為的習慣,能讓你少踩 90% 的坑。代碼評審時,把這 5 點作為必檢清單。