【MySQL】第13节|MySQL 中模糊查询的全面总结
以下是 MySQL 中模糊查询的全面总结,涵盖各种索引优化方案的核心原理、适用场景及操作示例:
一、模糊查询类型与索引优化方案
查询类型 | 示例语法 | 最佳索引方案 | 索引结构 | 适用场景 |
---|---|---|---|---|
前缀匹配 | LIKE 'prefix%' | 普通索引/前缀索引 | B-Tree | 用户名、路径、分类前缀查询 |
后缀匹配 | LIKE '%suffix' | 逆向索引/全文索引 | B-Tree/倒排索引 | 文件扩展名、URL 后缀查询 |
任意位置匹配 | LIKE '%word%' | 全文索引/搜索引擎(ES) | 倒排索引 | 文章关键词、内容搜索 |
函数计算匹配 | LIKE CONCAT('%', var, '%') | 函数索引/冗余字段 | B-Tree | 动态关键词搜索 |
二、前缀索引(Prefix Index)
核心原理
- 索引字段的前 N 个字符,而非全量内容,减少索引体积。
- 语法:
CREATE INDEX idx_col_prefix ON table_name(column_name(N));
适用场景
- 字段长度较长(如
VARCHAR(255)
)且前缀重复率低。 - 查询以固定前缀开头(如
LIKE 'user%'
)。
操作步骤
- 计算最佳 N 值:
SELECT COUNT(DISTINCT LEFT(column_name, N)) / COUNT(*) AS selectivity FROM table_name;
- 选择
selectivity
接近 1 的最小 N(通常 ≥ 0.95)。
- 选择
- 创建前缀索引:
CREATE INDEX idx_email_prefix ON users(email(20));
优缺点
- 优点:节省空间,提升前缀匹配性能。
- 缺点:仅支持前缀匹配,不支持后缀或中间匹配。
三、逆向索引(Reverse Index)
核心原理
- 将字段值反转后存储,并创建索引,将后缀匹配转化为前缀匹配。
适用场景
- 查询以固定后缀结尾(如
.jpg
、.pdf
)。 - 数据量较大且后缀查询频繁。
操作步骤
- 添加反转字段:
ALTER TABLE files ADD reversed_path VARCHAR(255) AS (REVERSE(file_path));
- 创建索引:
CREATE INDEX idx_reversed ON files(reversed_path);
- 查询时反转条件:
SELECT * FROM files WHERE reversed_path LIKE CONCAT(REVERSE('.jpg'), '%');
优缺点
- 优点:利用 B-Tree 索引优化后缀匹配。
- 缺点:需额外存储反转字段,查询时需计算
REVERSE()
。
四、函数索引(Functional Index)
核心原理
- 直接对表达式或函数结果创建索引,避免查询时重复计算。
适用场景
- 查询条件包含函数(如
SUBSTRING()
、LOWER()
)。 - 需对计算结果进行过滤(如提取文件扩展名)。
操作步骤
- 创建函数索引(MySQL 8.0+):
CREATE INDEX idx_extension ON files(SUBSTRING_INDEX(file_path, '.', -1));
- 查询时使用相同函数:
SELECT * FROM files WHERE SUBSTRING_INDEX(file_path, '.', -1) = 'jpg';
优缺点
- 优点:简化查询逻辑,避免手动维护冗余字段。
- 缺点:索引维护开销大(每次写入需重新计算)。
五、全文索引(Full-Text Index)
核心原理
- 使用倒排索引结构,将文本分词后建立映射关系,支持高效全文搜索。
适用场景
- 查询条件可能出现在文本任意位置(如
LIKE '%keyword%'
)。 - 需支持自然语言搜索(如权重排序、同义词匹配)。
操作步骤
- 创建全文索引:
ALTER TABLE articles ADD FULLTEXT INDEX ft_content(content);
- 查询语法:
-- 自然语言模式 SELECT * FROM articles WHERE MATCH(content) AGAINST('keyword'); -- 布尔模式(支持 + - 等操作符) SELECT * FROM articles WHERE MATCH(content) AGAINST('+apple -banana' IN BOOLEAN MODE);
配置优化
- 调整分词参数:
ft_min_word_len = 2 # 最小词长(默认 3) ngram_token_size = 2 # 支持中文分词
- 禁用停用词:
ALTER TABLE articles ADD FULLTEXT INDEX ft_content(content) WITH PARSER ngram;
优缺点
- 优点:支持任意位置匹配,性能优于
LIKE '%word%'
。 - 缺点:配置复杂,不支持精确位置匹配(如必须在开头)。
六、性能对比与选型建议
索引类型 | 查询效率 | 空间占用 | 维护成本 | 适用场景优先级 |
---|---|---|---|---|
前缀索引 | 极高 | 低 | 低 | 前缀匹配(如用户名、路径) |
逆向索引 | 高 | 中 | 中 | 后缀匹配(如文件扩展名) |
函数索引 | 高 | 中 | 高 | 需对函数结果过滤的场景 |
全文索引 | 高 | 高 | 高 | 任意位置模糊匹配(如文章搜索) |
七、注意事项与最佳实践
- 避免全表扫描:
- 尽量避免
LIKE '%word%'
(全表扫描),改用全文索引或 ES。
- 尽量避免
- 索引选择性:
- 对低选择性字段(如性别、状态码)创建索引意义不大。
- 覆盖索引:
- 确保查询字段都在索引中,避免回表:
CREATE INDEX idx_covering ON table_name(column_name) INCLUDE(other_column);
- 确保查询字段都在索引中,避免回表:
- 验证索引使用:
EXPLAIN SELECT * FROM table_name WHERE column_name LIKE 'prefix%';
- 检查
type
列是否为range
或ref
。
- 检查
八、常见问题排查
- 索引未生效:
- 检查查询条件是否包含函数(如
LOWER()
),导致索引失效。 - 使用
FORCE INDEX
强制优化器选择索引:SELECT * FROM table_name FORCE INDEX (idx_col) WHERE ...;
- 检查查询条件是否包含函数(如
- 全文索引不支持中文:
- 启用
ngram
分词器:ALTER TABLE articles ADD FULLTEXT INDEX ft_content(content) WITH PARSER ngram;
- 启用
总结
- 前缀匹配:优先使用前缀索引(简单高效)。
- 后缀匹配:逆向索引或全文索引(根据数据量选择)。
- 任意位置匹配:全文索引或 Elasticsearch(复杂场景)。
- 函数计算匹配:函数索引或冗余字段(权衡维护成本)。
通过合理选择索引方案,可将模糊查询性能提升数十倍甚至数百倍,避免生产环境出现慢查询瓶颈。