数据库分库分表
水平分表
把user表变成user_0到user_xx这样的表。
最常见的做法是根据ID取模分表,这样做法的缺点是表不易于扩展。
根据ID范围分表则易于扩展这张表,但缺点则是可能有某几张张表的读写压力过大,“一表有难,八表旁观”,这就是读写热点问题。解决读写热点问题最简单的方案是让ID变得随机,这样ID就能随机分散。
垂直分表
把某几列拆成一个新表,原来的表就变小了。
那么为什么会变快呢?
MySQL的底层结构是B+树,B+树本质上是一个个16K的数据页实现的,表里的一行行数据是放在数据页里面的。当要查询某个数据时,要把数据页加载到内存中,这就产生了磁盘IO。如果列的数量减少,那么一页中可以有更多的行,磁盘IO就可以减少,从而加快查询。
如果把不同的库部署到不同的机器上,就能充分利用各个机器的性能。不管是单库分表还是多库分表,都需要一个中间层逻辑做路由,对于业务代码来说就感受不到分库分表。
读扩散
在分库分表的数据库架构中,读扩散问题主要表现为:当查询条件不是分片键时,需要对所有分表都执行查询操作,随着分表数量的增加,查询次数也会不断增加。比如,数据库表以id作为分片键进行分表,但查询语句是select * from user where name = "小白";
,由于name不是分片键,无法确定具体要查询哪个分表,只能对所有分表都执行该查询,如果有100张分表,就需要执行100次查询,分表越多,查询次数越多,这就是读扩散问题。
解决方案
引入新表做分表
问题的核心在于主键是分片键,而普通索引列并不分片。可以单独建个新的分片表,这个新表里的列只有旧表的主键id和普通索引列,而这次换普通索引列来做分片键。当查询普通索引列时,先到这个新的分片表里做一次查询,迅速定位到对应的主键id,然后再拿主键id去旧的分片表里查一次数据。这样就从原来漫无目的的全表扩散查询,缩减为只查固定几个表。
但这样做缺点也很明显,这样做要维护两套表,并且更改时要两张表同时进行更改,开发量大
canal +elasticsearch解决读扩散问题
- canel同步数据到es
- es存放需要搜索字段和id
- 搜索到数据获得id,再去数据库根据id取数据