標準 LIKE '%keyword%' 無法使用索引,資料量超過百萬時全表掃描效能崩潰。本文分享一種利用 MySQL 全文索引(Full-text Index)配合字元級 N-gram 編碼,實現高效模糊搜尋的創新方案。
LIKE 'abc%' 可用索引(前綴匹配)LIKE '%abc'、LIKE '%abc%' 無法用索引 → 全表掃描MATCH AGAINST 搜尋「老鼠愛大米」可匹配「老鼠」、「大米」,但無法匹配「愛」、「鼠愛」等子字串
[mysqld]
ft_min_word_len = 1 -- 最小詞長設為 1(預設 4),允許單字元索引
ft_stopword_file = "" -- 禁用停用詞表,不忽略任何詞
重啟 MySQL 生效。
CREATE TABLE `tbl_search` (
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`name` VARCHAR(500) NOT NULL,
PRIMARY KEY (`id`),
FULLTEXT KEY `idx_name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4;
注意:InnoDB 5.6+ 也支援全文索引,但需設定 innodb_ft_min_token_size=1。
public static String encode(String input) {
if (input == null) return null;
StringBuilder output = new StringBuilder();
for (int i = 0, len = input.length(); i < len; ++i) {
char ch = input.charAt(i);
// 數字、大寫字母、全形數字/字母、底線、連字號:直接轉十六進位
if (ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z'
|| ch >= '0' && ch <= '9' || ch >= 'A' && ch <= 'Z'
|| ch == '_' || ch == '-') {
output.append(Integer.toHexString(ch)).append(' ');
}
// 小寫字母、全形小寫:轉大寫後再十六進位(統一大小寫)
else if (ch >= 'a' && ch <= 'z' || ch >= 'a' && ch <= 'z') {
output.append(Integer.toHexString(ch - 32)).append(' ');
}
// 中日韓統一表意文字、片假名、平假名:直接十六進位
else {
Character.UnicodeBlock block = Character.UnicodeBlock.of(ch);
if (block == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS
|| block == Character.UnicodeBlock.KATAKANA
|| block == Character.UnicodeBlock.HIRAGANA) {
output.append(Integer.toHexString(ch)).append(' ');
}
// 其他字元忽略
}
}
// 移除尾部空格
if (output.length() > 0 && output.charAt(output.length() - 1) == ' ') {
output.deleteCharAt(output.length() - 1);
}
return output.toString();
}
藍皮鼠200884dd 76ae 9f20 32 30 30 38name 欄位
-- 搜尋包含「皮鼠2」的記錄
SELECT * FROM `tbl_search`
WHERE MATCH(`name`) AGAINST('"76ae 9f20 32"' IN BOOLEAN MODE);
IN BOOLEAN MODE:啟用布林模式,支援雙引號精確短語匹配LIKE '%皮鼠2%' 但可使用全文索引| 優點 | 缺點 |
|---|---|
| 可使用全文索引,百萬級資料毫秒級回傳 | 需額外儲存編碼後字串(約 2-3 倍原長度) |
| 支援任意子字串搜尋(如 LIKE %abc%) | 寫入需額外編碼處理(應用層或 Trigger) |
| 利用 MySQL 內建全文索引,無外部依賴 | 中文分詞粒度為字,無法語義搜尋(需結合分詞器) |
| 布林模式支援 + - * 等豐富操作 | 全文索引更新有延遲,極高寫入場景需評估 |
LIKE '%...%' 明顯緩慢| 方案 | 適用性 | 複雜度 | 效能 |
|---|---|---|---|
| 全文索引 + N-gram 編碼(本文) | 短文本模糊搜尋 | 低(純 MySQL) | 高 |
| 前綴索引 + 反轉字串索引 | 前綴/後綴搜尋 | 中 | 中 |
| Trigram 索引 | 通用子字串 | 高(需外掛/pg_trgm) | 高 |
| Elasticsearch / Solr | 全文檢索、語義、聚合 | 高(外部系統) | 極高 |
| MySQL 8.0 ngram parser | 中文全文檢索 | 低(內建) | 高 |