需求:用戶輸入多個關鍵字 (空格分隔),需在多個欄位 (如 title、tag、description) 中**同時包含所有關鍵字**的記錄。本文對比 CONCAT 組合查詢、全文索引、應用層分詞三大方案優劣與適用場景。
CREATE TABLE `magazine` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
`title` VARCHAR(200) NOT NULL,
`tag` VARCHAR(500) NOT NULL,
`description` TEXT NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB;
用戶輸入:"MySQL 優化 索引" → 分割為 3 個關鍵字。要求:每個關鍵字必須在 title/tag/description 任意欄位中出現 (OR 關係),且**所有關鍵字都要滿足** (AND 關係)。
-- 動態構建 SQL (參數化防注入)
SELECT * FROM `magazine`
WHERE CONCAT(`title`, ' ', `tag`, ' ', `description`) LIKE '%MySQL%'
AND CONCAT(`title`, ' ', `tag`, ' ', `description`) LIKE '%優化%'
AND CONCAT(`title`, ' ', `tag`, ' ', `description`) LIKE '%索引%';
CONCAT 遇 NULL 結果為 NULL (需 COALESCE)、性能隨數據量線性下降。-- 1. 創建全文索引 (5.6+ InnoDB 支持)
ALTER TABLE `magazine` ADD FULLTEXT INDEX `ft_all` (`title`, `tag`, `description`);
-- 2. 自然語言模式 (默認,相關性排序)
SELECT *, MATCH(`title`,`tag`,`description`) AGAINST('MySQL 優化 索引' IN NATURAL LANGUAGE MODE) AS relevance
FROM `magazine`
WHERE MATCH(`title`,`tag`,`description`) AGAINST('MySQL 優化 索引' IN NATURAL LANGUAGE MODE)
ORDER BY relevance DESC;
-- 3. 布爾模式 (精確控制:+必含 -排除 *通配)
SELECT * FROM `magazine`
WHERE MATCH(`title`,`tag`,`description`) AGAINST('+MySQL +優化 +索引' IN BOOLEAN MODE);
ngram 解析器 (5.7.6+) 將中文按字/雙字拆分。
ALTER TABLE `magazine` ADD FULLTEXT INDEX `ft_all` (`title`, `tag`, `description`) WITH PARSER ngram;
ft_min_word_len (默認 4) 影響短詞;ngram 會產生大量 token 佔空間;停用詞表需維護;不支持「所有關鍵字在任意欄位」的精確 AND 邏輯 (布爾模式 +MySQL +優化 要求每個詞在索引欄位集合中出現,但無法區分具體欄位)。-- 8.0 虛擬列 (不佔存儲,自動維護)
ALTER TABLE `magazine`
ADD COLUMN `search_blob` TEXT GENERATED ALWAYS AS (CONCAT(`title`, ' ', `tag`, ' ', `description`)) VIRTUAL,
ADD FULLTEXT INDEX `ft_search` (`search_blob`) WITH PARSER ngram;
-- 或普通索引 (前綴) 配合 LIKE (仍無法解決 %keyword% 索引失效)
-- 此方案本質同方案一/二,不再贅述
| 維度 | CONCAT+LIKE | 全文索引 (ngram) | Elasticsearch |
|---|---|---|---|
| 數據量支撐 | < 10萬 | 10萬 - 500萬 | > 500萬 / 高併發 |
| 中文分詞 | 無 (按字符匹配) | ngram 字/雙字 | IK/jieba 詞級 (最準) |
| 「所有關鍵字任意欄位」邏輯 | 精確支持 | 近似 (布爾模式) | 精確支持 (bool query) |
| 相關性排序 | 無 | 內建 | 強大 (BM25/TF-IDF/自定義) |
| 維護成本 | 零 | 低 (DDL 同步) | 高 (集群運維、同步) |
| 部署複雜度 | 無 | 低 | 高 |
CONCAT + LIKE (加 COALESCE 處理 NULL)。FULLTEXT + ngram (調整 ngram_token_size=2 改雙字)。