MongoDB字符串字段索引失效主因是类型不匹配、顺序错误或未覆盖查询路径;需确保查询值类型与存储一致(如status必须为string)、遵循最左前缀原则,并用explain验证是否命中索引。

CreateIndex 之后查询还是慢?大概率是字符串字段的索引没对上——类型不一致、顺序错、或根本没建在查询路径上。
mongo.IndexModel 中字符串字段必须显式匹配 BSON 类型
Go 驱动不会自动转换类型。比如字段 "status" 在文档里存的是 "active"(string),但查询时用了 int64(1),哪怕索引存在也完全不命中。MongoDB 对 BSON 类型敏感,string 和 int64 是两个完全不同的索引分支。
- 查原始数据类型:
db.collection.findOne().status看实际存储值和类型 - 建索引前确认字段内容:用
bson.M{"status": bson.M{"$type": "string"}}过滤验证 - Go 里建索引时 Keys 用
bson.D{{"status", 1}}没问题,但查询条件必须也是 string,例如bson.M{"status": "active"} - 如果字段混存了
"1"和1,得先统一清洗,否则索引形同虚设
MySQL 中 VARCHAR 字段索引失效的常见写法
Go 用 database/sql 查 MySQL 时,WHERE name = ? 看似简单,但参数传错就绕过索引:
- 传入
nil或空字符串""会导致优化器放弃使用索引(尤其当该列允许 NULL) - 用
LIKE "%abc"—— 前导通配符让 B-tree 索引完全无效;改用LIKE "abc%"才能走索引 - 函数包裹字段:
WHERE UPPER(name) = 'ABC'无法利用name上的索引;应建函数索引(MySQL 8.0+)或在应用层预处理 - 字符集不一致:表用
utf8mb4_unicode_ci,但参数连接时用了latin1,隐式转换导致索引失效
复合索引中字符串字段的位置决定是否生效
MongoDB 和 MySQL 都遵循“最左前缀原则”。字符串字段放在复合索引中间或末尾,而查询只用了它,索引大概率被跳过:
立即学习“go语言免费学习笔记(深入)”;
- MongoDB 示例:索引
{"category": 1, "title": 1, "created_at": -1},但查询只写{"title": "Go教程"}→ 不命中 - MySQL 示例:索引
INDEX idx_cat_title (category, title),查询WHERE title = 'xxx'→ 全表扫描 - 正确做法:高频单字段查询的字符串字段,单独建索引;若必须复合,把等值查询字段(如
status)放最左,排序/范围字段(如created_at)放右 - ESR 原则(Equal, Sort, Range):等值条件字段优先,然后是排序字段,最后是范围字段(如
$gt/BETWEEN)
文本搜索场景下字符串索引选型差异
纯 = 查询用普通 B-tree 索引;模糊或全文匹配就得换策略:
- MongoDB:用
"text"索引支持{$text: {$search: "go lang"}},但注意它不支持$regex+ 索引组合,且不能与其他字段混在同一个复合索引里 - MySQL:用
FULLTEXT索引配合MATCH ... AGAINST,比LIKE "%x%"快得多;但不支持小于 4 字符的词(默认 ft_min_word_len=4) - 正则优化仅限前缀:MongoDB 中
/^go.*/能用普通索引加速,/.*go.*/依然 COLLSCAN - 大小写敏感问题:MongoDB 默认区分大小写;MySQL 取决于 collation,
_ci后缀表示 case-insensitive,建索引前得想清楚业务是否真需要大小写区分
最容易被忽略的一点:字符串字段建了索引,不代表查询就一定走它——explain 结果里看到 COLLSCAN 或 type: ALL,第一反应不该是“索引没生效”,而是“这个查询条件压根没资格用上它”。先看字段类型、再看查询模式、最后看索引结构,三者缺一不可。


















