在 MySQL 中,LIKE '%keyword%' 會導致全表掃描,無法利用索引,數據量大時性能極差。本文介紹四個字符串查找函數 LOCATE、POSITION、INSTR、FIND_IN_SET,它們在特定場景下比 LIKE 更高效,並提供實戰對比與選型建議。
| 函數 | 語法 | 返回值 | 特點 |
|---|---|---|---|
LOCATE(substr, str[, pos]) | LOCATE('bar', 'foobarbar') → 4LOCATE('bar', 'foobarbar', 5) → 7 | 首次出現位置 (1-based),不存在返回 0 | 支援指定起始位置 pos,多字節安全 |
POSITION(substr IN str) | POSITION('bar' IN 'foobarbar') → 4 | 同 LOCATE 兩參數版 | SQL 標準語法,參數順序相反,可讀性強 |
INSTR(str, substr) | INSTR('foobarbar', 'bar') → 4 | 同 LOCATE 兩參數版 | 參數順序與 LOCATE 相反,Oracle 兼容 |
FIND_IN_SET(str, strlist) | FIND_IN_SET('name1', 'name1,name2') → 1 | 在逗號分隔列表中的位置 (1-based),不存在返回 0 | 專為 SET 類型或逗號分隔字符串設計,常數優化可用位運算 |
LIKE '%kw%',函數調用開銷略低,且在某些版本中優化器能更好估算成本。適用於 逗號分隔的枚舉值存儲 (如標籤、分類、權限列表)。
-- 表結構
CREATE TABLE test (id INT, tags VARCHAR(255)); -- 存儲 'tag1,tag2,tag3'
-- 查詢包含 'tag2' 的記錄
SELECT * FROM test WHERE FIND_IN_SET('tag2', tags) > 0;
優勢:
LIKE '%,tag2,%' 的邊界匹配錯誤 (首尾無逗號)。SET 類型,優化器使用位圖運算,極快。局限:
若業務高頻模糊查詢,應從架構層面解決:
ALTER TABLE t ADD FULLTEXT(col); SELECT * FROM t WHERE MATCH(col) AGAINST('keyword'); (MyISAM 5.6+/InnoDB 5.6+)。entity_tags(entity_id, tag_id),建立索引,JOIN 查詢極快。LIKE 'keyword%' 可用索引,僅後綴/中間模糊無法用索引。LOCATE/INSTR 代替 LIKE 碼更簡潔。FIND_IN_SET,長期規劃拆表。