一般普通业务系统来讲,数据量都比较少,基本百万级别就很多了,再多的话就上 ES 来做查询了,比如之前做的 SSO 系统瞬时并发量几万是很正常的数据,肯定不能用数据库来做查询,这次恰好有个有很大数据,但是没用 ES 的场景,所以就小小尝试下优化试试。
分表
应该很多人听过一个小故事,QQ 的分表就是根据 QQ 号的每一个数字就行分表,具体如何咱也不知道,咱这次也模仿下这种分表方式。
目前有 users 表,共有近千万数据,id 是自增的,所以直接根据 id 进行分表。
首先创建分表:
create table user_1 like users;
create table user_2 like users;
create table user_3 like users;
...
拆分数据:
INSERT INTO user_1 SELECT * FROM users WHERE id BETWEEN 1 AND 1000000;
INSERT INTO user_2 SELECT * FROM users WHERE id BETWEEN 1000001 AND 2000000;
INSERT INTO user_3 SELECT * FROM users WHERE id BETWEEN 2000001 AND 3000000;
...
查询
直接按照最常用场景来执行查询任务,查询 state 字段中包含 n
字符的数据,既 state like '%n%'
首先是数据库执行看看效率:
select id, name, email, phone, company from users where state like '%o%' order by id desc limit 20 offset 5000000;
执行耗时 10.17 秒,而且会随着 offset 的增加而增加,比如 offset 为 0 时其实可能只需要几纳秒。
来到程序中,从程序中进行查询(这里使用游标进行查询):
因为具有 offset 和 where,我们不知道数据可能会散落在哪里,所以需要拿出所有匹配到的数据,一张子表要六十多万数据,所以这里会发现很慢。
加上日志发现,耗时其实是在数据实例化部分,单纯的查询其实很快很快。
相比直接查询是有了一点点时间上的优化,但就这样来讲,距离可用性还是差了十万八千里,目前网上搜到的解决方案也都是对于无筛选情况下的处理,比如把 offset 替换成 where id >
,就算是千万级别的数据也跟查询第一页一样,因为不需要逐行扫描,直接跳过了,如果这样做的话,其实不用分表都够用了。
总结
目前看下来,对于没有精确筛选的数据来说很好优化,简单的根据规律列执行跳过即可,count 也可以放到外部数据中或者不显示其实都行。最主要的优化手段就是减少查询筛选范围,分表其实也是针对限定范围,但是局限性都比较大,对于复杂查询就无解了,那这样我觉得可以考虑更换特定数据库存储,或者使用例如 Elasticsearch 这种更加实用些。