当数据量日益增长,查询性能不断下降,我们将不得不对数据表进行拆分,当我们数据表在进行了水平拆分后,分页查询将会收到一些限制,并且针对于不同的分表策略,分页的规则也会有所不同。
背景
随着项目上线时间的不断变长,数据表的数据量不断增多,查询速度日渐变慢,客户反馈系统响应慢。当数据表达到一定量级之后,且垂直拆分无效之后,就需要对数据进行水平分表,水平分表是一个难点,我们需要考虑多方面内容,需要去衡量自己的业务增长,选对分表方式能够有效的降低数据便宜,使扩容更加平滑。当业务增长缓慢,但当系统使用久之后出现性能问题,我认为抽离历史数据也是不错的方案。
分库分表方案选型可参考之前文章收好这份武林秘籍,让你分库分表再无烦恼。
当我们水平分表之后,困扰我们另一个问题就是分表查询了,下面我们就来探讨一下,数据打散在各个分表,我们该采取什么方式,高效的聚合数据,并能按照一定规则排序分页。
方案
方案一 分表键查询
分表后,使用最多的查询条件无疑是分表键,比如说我们以用户ID为分表键,当我们查询某一用户的具体信息时,就直接可以通过分表键路由到该键所在的库中查询。这样单个库就可以支持我们分页及排序。
方案二 非分表键的关键键查询
就用最经典的电商案例举例,最常用的查询无非是买家查询与卖家查询,一般这种时候会采用数据冗余的方案,基于买家和卖家分别做一套分表,当以买家为查询条件路由到买家分表,当以卖家为条件,路由到卖家分表,这种就是典型的空间换时间。
具体落地的时候可以某一方为主,负责写入,另一方只提供查询服务,通过订阅bin log自动生成。
方案三 全量冗余
除了分表键,关键键查询,其他的查询该采用什么方案,一般来说大部分公司会采用OLAP的数据库全量冗余一份数据,这种数据库特点就是不支持事务,查询速度快,支持大数据量。
方案四 全局查询再聚合
当我们在使用非分表键,且没有冗余数据的时候查询就会有多种情况出现
例如:数据都在某一张表中、数据在每个表一半、数据每一个表包含一部分
在查询的时候我们并不清楚,数据会怎么分配,就只能把每个表都满足的数据查出来,再排序,分页
将 limit x,y 改写成 limit x + y
然后在内存中排序,然后再limit y
优点: 业务无损,精准查找
缺点: 每个库表返回大量数据开销大,需要二次排序浪费算力,深度分页性能极速下降
优化方案:
-
禁止跳页,每次查询带着上一页条件,减少深度分页性能下降问题
-
a. 二次查询,分表数为n,将 limit x,y 改写成 limit x / n,y
b. 取n个表排序字段最小值 min,以及每个表排序字段最大值 max_n
c. 排序字段 between min and max_n
d. 然后汇总在内存中,然后再排序分页
-
允许精度丢失,分表数为n,将 limit x,y 改写成 limit x / n,y /n,然后聚合结果