概述
这篇文章没什么太多的干货,纯纯是一篇讨论和思考帖。
从业数据库领域三年有余了,从分库分表中间件到数据库团队内核学到了很多东西。也接触了很多项目,包括TiDB、Vitess、Polardb、StarDB等等。
国内的项目好像很多都聚焦于分库分表的概念,包括很多的数据库团队都在尝试这个概念的落地和沉溺于性能的跑分。
最近我在预览MySQL官方,看到了Partitioning的概念,而且占据了很大的篇幅。不由得引人思考,为什么这个概念在我接触的业务中没有被广泛的使用呢?或许我们将来可以有分库分区的概念?
接下来从头缕一下数据库选型的问题吧(以下均以MySQL的Innodb场景为例):
分表、分区、分库有什么用处
在那个远古的时代,物理机器的配置很低,当数据量增大的时候,传统的B+树的高度会越来越高,我们对硬件资源的要求很高,机器往往内存爆仓、IO打满等等。
这导致:
查询速度显著下降。复杂的查询、索引失效、全表扫描等操作变得缓慢。
在大表中创建和维护索引可能会消耗大量的时间和资源。插入、更新和删除操作可能需要花费更长的时间来维护索引,导致性能下降。
读写操作可能导致锁冲突,降低系统的并发处理能力,甚至引发死锁问题。
备份、恢复、数据清理、空间管理等操作变得困难,维护成本和风险增加。
等等。。
后来我们引出了第一个概念:分表
分表
在 5.1版本以前,MySQL并没有分区的概念,为了解决这个问题,无非是单表拆成双表、多表之类的,这样将一个表要面临的问题分散成了两个表或者多个表共同承受。
反思当下,在当前这个物理资源冗余的时代,大部分业务场景下我们的单表真的会比分表的性能差很多吗?有多少时候我们是为了分表而分表?我们的分表逻辑或许需要我们支持更多的功能,比如弹性、事务、一些查询语句的改写,然后一遍一遍的造轮子给运维带来无尽的痛苦。
分库
分表的解决能力还是有限的,我们一台物理机器的能力也是有限的,这时候或许我们可以采用分表的形式,来避免热点问题或者单机器压力过载的问题。
将一个库要面临的问题分散成了两个库或者多个库共同承受。
分区
相关文档
在5.1版本以后MySQL出了一个国内几乎无人问津的分区表的功能。
分区表的实现原理其实和分表差不太多,不过它更靠近文件系统,而没有经过MySQL的应用层或者引擎层。MySQL的物理数据,存储在表空间文件(.ibdata1和.ibd)中,这里讲的分区的意思是指将同一表中不同行的记录分配到不同的物理文件中,几个分区就有几个.idb文件。
随着 MySQL 版本的更新迭代,分区功能也在后续版本中不断得到改进和增强。具体的分区功能支持情况如下:
•MySQL 5.1:引入了 Range 和 List 两种分区类型。支持基本的分区管理和查询优化。
•MySQL 5.5:对分区表的查询优化有所改进,提升了性能。
•MySQL 5.6:引入了更多的分区管理功能,包括 subpartition 子分区、分区交换操作、CHECK 约束等。
•MySQL 5.7:进一步增强了分区表的功能,包括 hash 分区类型、NOWAIT 选项、ALTER TABLE … EXCHANGE PARTITION 和 ALTER TABLE … REBUILD PARTITION 等操作。
•MySQL 8.0:继续对分区表进行优化和增强,包括对于自动生成分区键值、分区表的查询性能提升等方面的改进。
这样看起来,这不完全Cover住了分表的概念吗?甚至,这不比业界的分表做的还要好吗。
那为什么我们还要痴迷于分表,或许我们可以采用分区的逻辑吧?
当然,还有一些延伸到运维操作,举个例子:
分区表怎么扩容
详见 ALTER TABLE 语句
1.创建新分区:使用 ALTER TABLE 命令添加新的分区。例如,如果是按照时间范围分区的表,可以增加新的时间范围的分区。
ALTER TABLE your_partitioned_table
ADD PARTITION (PARTITION p_new VALUES LESS THAN (new_value));
这里的 new_value 是新的分区范围。
2. 数据迁移:使用 ALTER TABLE … REORGANIZE PARTITION 命令将现有分区中的数据迁移到新的分区中。例如,可以通过将旧分区的数据移动到新分区来实现。
ALTER TABLE your_partitioned_table
REORGANIZE PARTITION old_partition INTO
(PARTITION p_new VALUES LESS THAN (new_value));
这里的 old_partition 是要移动数据的旧分区。
3. 数据清理(可选):在确认数据迁移成功后,可以考虑清理不再需要的旧分区。使用 ALTER TABLE … DROP PARTITION 命令可以删除不再需要的旧分区。
ALTER TABLE your_partitioned_table
DROP PARTITION old_partition;
这里的 old_partition 是要删除的旧分区。
显而易见,这是一个原地扩容操作,我们或许不需要引入什么复杂的组建或者逻辑去做resharding。
落地方案猜测
我们或许可以在单表业务场景下遇到问题瓶颈后采用分区的概念,如果分区不够可以采用原地扩容逻辑。当机器达到瓶颈后采用分库的概念达成分库分区的逻辑。
这只是一个猜想,对于我们的数据库厂商,其实只需要将这套逻辑维护好做到高可用的逻辑即可。
当然,围绕着分区和物理数据库我们还有很多扩展内容可以去做,但是这篇文章旨在说明,或许我们不应该被分库分表约束了思维,或许我们不需要做分布式的逻辑,或许在机器性能良好的场景下我们单机器就可以cover住我们的数据量。
此外,一个数据库产品或许应该做到serverless的概念,我们用户不需要理解这么多的逻辑,至于分区或许这个看MySQL文档都可以学习到。