为什么要使用 ElasticSearch?和传统关系数据库(如 MySQL)有什么不同?
结论先行:MySQL 擅长“按主键或索引精确定位、强事务、行级更新”,Elasticsearch(ES)擅长“全文检索、相关性排序、海量数据聚合”。用 MySQL 做 like '%关键词%' 是全表扫描且无法排序相关性;用 ES 做账务扣减则没有事务。两者是互补关系,不是替代关系。
一、能力对照
| 维度 | MySQL | Elasticsearch |
|---|
| 数据模型 | 行 + 列,强 Schema | JSON 文档,动态映射 |
| 索引结构 | B+ 树 | 倒排索引 + DocValues 列存 |
| 检索方式 | 等值、范围、前缀 | 分词、模糊、短语、相关性打分 |
| 事务 | ACID,行锁 | 无跨文档事务,单文档原子 |
| 实时性 | 提交即可见 | 近实时,默认 1 秒 refresh |
| 扩展 | 分库分表,改造量大 | 原生分片,水平扩展 |
| 聚合 | group by,大数据量吃力 | terms/date_histogram,亿级可接受 |
| 存储成本 | 低 | 高(倒排 + 正排 + 副本) |
二、典型使用姿势
-- MySQL:前缀匹配还能走索引,前后模糊只能全表扫
SELECT id, title FROM article WHERE title LIKE '%分布式锁%';
// ES:分词后按 term 匹配,还能按相关性排序
GET /article/_search
{
"query": {
"match": { "title": "分布式锁" }
},
"sort": ["_score", { "publish_time": "desc" }]
}
match 会先对查询词分词,再与倒排索引求交,最后用 BM25 算相关性;like '%x%' 只能逐行比较字符串,数据量大时必然超时。
三、什么场景该上 ES
| 场景 | 说明 |
|---|
| 站内搜索 | 商品、文章、日志的关键词检索 + 排序 + 高亮 |
| 日志分析 | ELK 组合,按时间范围 + 关键字 + 聚合统计 |
| 多维筛选 | 电商筛选项组合(品牌、价格区间、标签) |
| 模糊匹配 | 拼音、同义词、纠错、分词 |
| 大表聚合 | 亿级数据的 terms 统计,MySQL 难以承受 |
四、什么场景不该上 ES
| 场景 | 原因 |
|---|
| 强事务(转账、库存扣减) | 无跨文档事务与回滚 |
| 频繁更新同一条记录 | 更新是“标记删除 + 新建文档”,段合并成本高 |
| 精确主键查询为主 | MySQL 更省资源,ES 反而更慢更贵 |
| 数据量很小 | 引入集群运维成本不划算 |
| 需要 join | ES 的 join 能力弱,nested 有性能代价 |
五、引入 ES 的真实成本
| 成本项 | 说明 |
|---|
| 存储 | 倒排 + 正排 + _source,通常是原文的 2~3 倍,还要乘副本数 |
| 机器 | 检索吃 CPU 与堆外内存,需要独立集群,不能和业务混部 |
| 同步链路 | 双写或 binlog 订阅,多一条必须监控的链路 |
| 运维 | 分片规划、段合并、快照备份、版本升级都有坑 |
| 一致性 | 只能做到最终一致,前端要接受秒级延迟 |
只有当“检索体验带来的收益”大于这些成本时才值得上;如果只是按 ID 查详情,MySQL 加索引更划算。
常见追问
- 追问:能不能用 ES 做主存储?不建议。它没有事务、近实时、段合并会抖动,恢复与备份能力也弱于数据库;主流做法是 MySQL 存权威数据,ES 做检索副本。
- 追问:ES 会不会丢数据?默认
refresh_interval=1s、translog 每 5 秒或每次请求后落盘,极端情况下可能丢最后一段时间的数据;可以设 translog.durability=request 换取更高可靠性。
- 追问:两者数据怎么同步?双写、事务消息、binlog 订阅(Canal)三条路,工程上多用 binlog 订阅 + 补偿对账。
小结
- MySQL 保正确性,ES 保检索体验,职责不同。
- 倒排索引 + 相关性打分是 ES 的独有能力,B+ 树做不到。
- ES 无跨文档事务、近实时、写入放大,不适合当权威存储。
- 上 ES 之前先问:是否真的需要分词、相关性、海量聚合。