mysql 的这个痛点,用 elasticsearch 轻松解决

智数映风鹤
• 阅读 2528

大家好,我是月白。

写这篇文章不是对比 mysql 和 elasticsearch 的优劣(它们生而不同,没啥好比的),而是想分享一下最近在工作上遇到的一个查询问题和这个问题的解决过程。对于 elasticsearch,我也还是处在略懂阶段,要不是因为这次工作需要,我可能不会去研究它😂

好了,回到正题,由于内部工作调整,接收了一个公司的边缘项目,体量并不大,几十万的用户数量。然而,就是这区区的几十万用户数量,导致了mysql in 查询参数过多的问题,运营在管理后台查询客户列表速度缓慢甚至一度陷入瘫痪。

你可能会想,是不是代码写的太烂了或者前期设计考虑不周?

mysql 的这个痛点,用 elasticsearch 轻松解决
其实这个也能理解,毕竟产品的需求是多变的,考虑不周是常有的事。这个列表查询原本只有几个简单的字段查询,而且都是客户表单表内的字段查询,随着产品的变更,查询条件多达十几个,其中这个标签查询,联表也解决不了问题,那具体是怎么一个情况呢?

别急,让我简单介绍一下
mysql 的这个痛点,用 elasticsearch 轻松解决

问题简述

为了集中于描述这个问题,表结构进行了惨无人道的简化,能体会到这个意思就好😂
前端的展示就是下面这种分页表格(图片截图自 ant design 官方文档)
mysql 的这个痛点,用 elasticsearch 轻松解决

表结构

客户表 custmers

字段类型
idint
namestring
gendertinyint
ageint
remarkstring
created_attimestamp
updated_attimestamp

标签表 tags

字段类型
idint
namestring
created_attimestamp
updated_attimestamp

关联表 customer_tag

字段类型
customer_idint
tag_idint

查询需求

现在产品需要通过客户名字以及客户身上的标签进行查询,支持多个标签同时查询。原来的sql大概是这样的

/*
 获取符合要求的 customer_id 列表 
 查出来一大堆 customer_id
 */
select customer_id from custmer_tag where tag_id in (传入的tag_id);

/*
 通过 customer_id 查询
 每翻一页都得经历这一大堆id的in查询,id过多还会导致代码直接崩溃
*/
select * from customers where id in (一大堆id) limit 10 offset 0; 

问题显而易见了吧,in 查询内参数过多,不仅效率低下,极端情况还会导致sql过长程序崩溃。

看了第一眼我觉是不是可以拯救一下(慢就慢一点,先让程序不异常),于是换成下面的语句:

select * from customers where id in (select customer_id from custmer_tag where tag_id in (传入的 tag_id) group by customer_id));

但是仔细看了一下业务逻辑我就放弃了,多个 tag_id 查询 要支持 and 和 or 的查询逻辑,select customer_id from custmer_tag where tag_id in (1,2,3) group by customer_id 这句子查询 sql 就是 or 关系查询,customer 只需要存在任何一个 tag_id 就满足查询条件。但是如果是 and 逻辑呢?要查出同时存在标签 1,2,3 的客户,那么这条语句就不适用了。当然,如果一定要用 sql 去查,也许也能查出来,这里我就没有再试了,毕竟就算子查询行得通,效率也是十分低下的,不是长久之计。

解决方案

那该如何解决呢?我的第一反应就是先通过 es 查询出符合条件的 customer 表的 id,然后再通过id查询数据,这样对整个业务逻辑改动最小,效率也完全没有问题,毕竟原来的查询及组装数据逻辑十分复杂,涉及到五六张表联查和后续数据处理,实在不想做过多改动(常规职场保命)
mysql 的这个痛点,用 elasticsearch 轻松解决

开始优化

搭建 elasticsearch 服务

这个是运维的活,我提需求就行了。

数据写入 es

这个得我干了😅
由于需要查询的字段涉及了多张表,索性把所有相关字段和customer的基本信息写入到 es,方便后续同样需要查询的业务(后面还真的用到了,而且还追加了字段)

字段确定了之后,如何实时更新呢?在每个业务修改和插入的点触发写入和更新的操作?
显然不是,这样写既容易写不全面,也需要很大的机械化工作,显然不是生活在水深火热之中的程序员该干的事。那么怎么做呢?

这时候,如果我们能像mysql从库那样,把数据都同步过来,然后我们更新一下 es,岂不是完美。说干就干,在通过一番折腾之后(主要是监听binlog),终于是解决了数据入库的问题。

重构代码

现在的代码逻辑变成了这样:

  1. 从 es 分页查询出 customer id 100, 200, 300
  2. 把原来 sql 的所有 where 条件删除,添加 where id in (100,200,300),其他逻辑不用动

至此,业务重构完成,查询速度轻轻松松提高百倍,那缺点是什么呢?

!!!要花钱!!!!!
mysql 的这个痛点,用 elasticsearch 轻松解决

后话

虽然问题目前是解决了,但从这件事中,我体会到了 es 便利之处,决定进一步学习一番。这篇文章涉及到的 es 和 mysql 监听等相关内容后续更新吧!

就酱,祝大家工作顺利!我是月白,一枚在互联网苟且偷生的猿。

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Stella981 Stella981
3年前
Python将字符串转换成ObjectId类型
MongoDB自动生成的_id是ObjectId类型的。我需要将MongoDB的_id存到ElasticSearch中,而ElasticSearch又只能存String类型的_id,所以就涉及到两种类型的转换。ObjectId类型—→String类型这个非常简单
Easter79 Easter79
3年前
Springboot整合elasticsearch以及接口开发
Springboot整合elasticsearch以及接口开发搭建elasticsearch集群搭建过程略(我这里用的是elasticsearch5.5.2版本)写入测试数据新建索引book(非结构化索引)PUThttp://192.168.100.102:9200/book
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
ES某节点CPU增长至100%的诡异问题
这是一个从事发到目前为止我没有从根本上解决的技术问题,也是我心中的一个非常大的疑惑。写于:20200614周日,下午14:00问题已解决,解决过程和方案可以看文章最末尾,解决方案写于2020062015:26问题一:2020年6月4号上午10点左右(高峰期),A集群某节点,我们姑且称之为37号节点,CPU增长至100%
Stella981 Stella981
3年前
ELK学习笔记之ElasticSearch的索引详解
0x00ElasticSearch的索引和MySQL的索引方式对比Elasticsearch是通过Lucene的倒排索引技术实现比关系型数据库更快的过滤。特别是它对多条件的过滤支持非常好,比如年龄在18和30之间,性别为女性这样的组合查询。倒排索引很多地方都有介绍,但是其比关系型
为什么mysql不推荐使用雪花ID作为主键
作者:毛辰飞背景在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究
CoderCraber CoderCraber
2年前
解决Elasticsearch相关CORS问题
解决Elasticsearch相关CORS问题运行环境我用Java编写了一个带有ElasticSearch的后端,并使用Maven进行构建和管理。部署的运行环境是基于GoogleCloudPlatform(GCP)的。我在此环境中使用Google的Elas
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
美凌格栋栋酱 美凌格栋栋酱
5个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
智数映风鹤
智数映风鹤
Lv1
那些说好的不分离最后都被时间打磨成了不联系.
文章
2
粉丝
0
获赞
0