MySQL 全文检索性能优化:LIKE 查询拖慢主库?Canal 同步 ES + 增量实时更新!

公司的后台管理有一个搜索功能,搜订单备注里的关键词。刚开始数据量小,MySQL 的 LIKE '%keyword%' 还能跑。后来订单涨到几百万条,一个模糊搜索要跑 8 秒。更倒霉的是,这个搜索请求直接打在主库上——索引走不了,全表扫描,CPU 飙到 90%,其他正常业务也跟着慢。

LIKE '%xxx%' 是数据库的噩梦。前导通配符导致索引完全失效,只能全表扫描。MySQL 虽然也有 FULLTEXT 索引,但中文分词烂、不支持复杂排序、而且仍然在主库上消耗资源。

今天聊聊怎么用 Canal 把 MySQL 的数据实时同步到 Elasticsearch,把搜索的活从主库彻底拆出来。


架构:主库只管写,搜索交给 ES

MySQL(主库)                     Elasticsearch
  │                                  │
  │ INSERT/UPDATE/DELETE             │
  ├──── Canal 监听 binlog ──────────→├─ 增量同步
  │                                  │
  │ 业务读写                         │ 全文搜索
  │ (走主库)                        │ (走 ES)

Canal 伪装成 MySQL 的 Slave,订阅 binlog 的变更事件。任何 INSERT、UPDATE、DELETE 都会在毫秒级内被 Canal 捕获,然后转发给 ES。用户在后台搜东西的时候,直接走 ES 的搜索接口,主库完全不受影响。


Canal 怎么工作的

原理不复杂——MySQL 的主从复制所有从库都是一样的,Canal 只是假装自己是一个从库:

MySQL Master
  │
  ├─ 写 binlog
  │
  ├─ Slave(真正的从库)拉 binlog
  │
  └─ Canal(伪装从库)拉 binlog
       │
       ├─ 解析 binlog 事件
       ├─ 过滤需要的表
       └─ 转成 ES 文档 → 更新 ES

你的业务代码不用改一行——Canal 是旁路的,它不参与你的业务流程。你该 INSERT 还是 INSERT,Canal 在后台默默把数据搬到 ES。


增量同步的关键:顺序和去重

Canal 发过来的 binlog 事件是有序的——同一个事务内的操作保证顺序。但 Canal 到 ES 这条链路上,如果用了多线程消费,顺序可能被打乱。

解决办法:按主键哈希分区,同一个主键的操作始终发给同一个线程。 这样保证同一条记录的 UPDATE 一定在 INSERT 之后执行,DELETE 一定在 UPDATE 之后执行。

去重也很简单:ES 的文档 ID 用 MySQL 的主键。 同一条记录多次 UPDATE,ES 侧多次 Index 请求,后面的覆盖前面的,最终结果一致。


全量 + 增量两阶段同步

首次上线时需要把 MySQL 的历史数据全量同步到 ES。之后的增量由 Canal 接管。

上线流程:
  1. 全量:SELECT * FROM table → 批量写入 ES
  2. 记录全量完成时的 binlog 位点
  3. 增量:Canal 从该位点开始消费
  4. 全量和增量之间的窗口 → Canal 会补上

全量同步时注意别用单线程一条条写——几十万条数据写到明年去了。用 bulk API,每次 500~1000 条,吞吐量能到每秒几万条。


ES 侧要关注什么

Mapping 设计:需要搜索的字段用 text 类型(会分词),不需要搜索的用 keyword(精确匹配)。中文一定要用 ik_smart 分词器,不然搜"苹果"可能拆成"苹"和"果"。

写入优化:同步期间可以临时调大 refresh_interval 到 30s,减少 refresh 开销。全量同步完后恢复到默认 1s。

查询优化:ES 的 match 查询天然支持分词 + 排序 + 高亮。一个 LIKE '%keyword%' 要扫全表的查询,在 ES 里就是一次倒排索引查找,毫秒级。


总结

LIKE '%xxx%' 不是不能用——数据量小的时候没问题。但一旦数据量上来了,把搜索从主库拆出去是早晚的事。

三步走:

Canal 监听——伪装成 MySQL 从库,实时订阅 binlog。零侵入,原业务代码不动。

ES 接管搜索——模糊搜索、全文检索、复杂排序全交给 ES。主库不扫表,CPU 省下来给核心业务。

全量+增量——历史数据批量写入,增量 Canal 实时追。中间窗口自动补齐。

这套方案落地的成本主要在运维——多了一个 Canal 和一个 ES 集群。但收益是搜索性能从 8 秒降到 50 毫秒,主库 CPU 从 90% 降到正常水平。


有用的话转给还在主库上跑 LIKE '%xxx%' 的同事。


标题:MySQL 全文检索性能优化:LIKE 查询拖慢主库?Canal 同步 ES + 增量实时更新!
作者:jiangyi
地址:http://jiangyi.space/articles/2026/06/16/1781422978066.html
公众号:服务端技术精选
    评论
    0 评论
avatar

取消