函數定義
FIND_IN_SET(str, strlist)
-- 回傳 str 在 strlist 中的位置 (1-based),找不到回傳 0
-- strlist 格式:'a,b,c,d' (逗號分隔,無空格)
典型應用:權限位元組存儲
-- user 表
id | username | purview (VARCHAR)
1 | alice | '1,3,5'
2 | bob | '2,4'
-- 查擁有權限 1 的用戶
SELECT * FROM user WHERE FIND_IN_SET('1', purview) > 0;
優缺點分析
| 優點 | 缺點 |
| 單欄位存多值,減少關聯表 | **違反第一正規化 (1NF)**,原子性破壞 |
| 查詢語法簡潔 | **無法使用索引** (全表掃描),大量資料極慢 |
| 避免 JOIN 開銷 | 更新複雜 (需字串拼接/替換),易產生臭蟲 |
| 適用靜態、小量、唯讀場景 | 聚合統計 (如統計每個權限人數) 需掃全表 |
效能實測 (參考)
- 10 萬筆資料,`FIND_IN_SET` 全表掃描 ~200ms
- 同資料正規化 `user_permission` 表 + 索引,JOIN 查詢 ~2ms
- **差距 100 倍**
最佳實務建議
- **新系統嚴禁**此設計,採用**多對多關聯表** (`user_id`, `perm_id`)
- **舊系統若必須維持**:
- 資料量 < 1 萬可接受
- 加 `CHECK (purview REGEXP '^[0-9]+(,[0-9]+)*$')` 限制格式
- 唯讀查詢可建立**物化視圖** 或 **觸發器同步正規化表**
- 查詢時 `FIND_IN_SET('1', purview)` **優於** `purview LIKE '%,1,%' OR purview LIKE '1,%' OR purview = '1'` (邏輯完整、可讀性高)
結語
`FIND_IN_SET` 是**歷史包袱**的權宜之計。**新專案請正規化設計**,舊專案評估遷移成本,若無法遷移請控制資料量並輔以同步索引表。
- 上一篇文章: Windows CMD 連線 MySQL 入門:從啟動 cmd 到執行 SQL 完整圖文步驟
- 下一篇文章: MySQL 自增欄位插入 0 值解決方案:NO_AUTO_VALUE_ON_ZERO 模式完整指南
Copyright ©
程式碼之家 All Rights Reserved