赞
踩
这是亿级别表优化的第二篇,对第一篇感兴趣的可以看看。
距上次写亿级别优化已经有一个多月了,这段时间也没闲着,Q1 对模型做了梳理,重构了这部分业务,主要做了下面这些优化
所以,我还是总结这段时间成果吧!分享这次优化的经验。
距离上次数据量统计,数据已经增长了 2000W。
垂直分库是指根据业务来分库,不同的业务使用不同的数据库。例如,营销自动化业务和营销活动都存在高并发场景,如果使用同一个库,会占用一定的连接数,所以我们可以将数据库分为营销自动化库和营销活动库。在一些特定情况下我们还会分集群,不同业务模块使用不同集群。
垂直分表则是指把一张表中的字段,拆分为多张表(我习惯性称为子表或者附表)将数据散落在多张表内,一开始将一些不经常使用的字段拆分到另一张表中,亦或是在迭代过程中扩展子表来满足需求(迭代中扩展子表的方式在之前版本中前尝试过,扩展了好几张表最后都合并了,随着业务需求增加,数据查询越来越复杂,最后舍弃了这种方式)。
水平切分(分表)是按照某种规则,将一个表的数据分散到多个物理独立的数据库服务器中,形成“独立”的数据库“分片”。一般是按照 Range 或 Hash 取模。
Table Partition 是指根据一定规则,将数据库中的一张表分解成多个更小的容易管理的部分。从逻辑上看只有一张表,但是底层却是由多个物理分区组成。
在 TiDB 中分区表是一个独立的逻辑表,但是底层由多个物理子表组成。物理子表其实就是普通的表,数据按照一定的规则划分到不同的物理子表类内。程序读写的时候操作的还是逻辑表名字,TiDB 服务器自动去操作分区的数据。
想了解更多参考以下文档
TiDB 源码阅读系列文章(二十)Table Partition | PingCAP
Range 分区、Range COLUMNS 分区、Range INTERVAL 分区、List 分区、List COLUMNS 分区、Hash 分区、Key 分区。想了解更多语法和案例参考以下文档
早期对业务未来发展判断不准确以及过度设计,认为每个数据模型都应该满足数据库三范式,但付出的代价也非常高昂。
这次梳理模型的原则是比较简单的。
在单表单库下,当数据表的数据量逐渐累积到一定的数量时,操作数据库的性能会出现明显下降,即使我们使用索引优化,性能依然会存在瓶颈。如果每日数据增长大,我们应该考虑分表。
面对大量数据,除了单表的性能比较差以外,数据库连接数、磁盘 I/O 以及网络吞吐等资源都是有限的,并发能力也是有限的。所以,在一些大数据量且高并发的业务场景中,也需要考虑分表分库来提升数据库的并发处理能力。
分库分表业界方案都是很成熟的,有两种方案,垂直切分和水平切分两种。名词解释那节已经解释过了,这里不过多解释。
分库分表依赖数据库中间件,但是,某些数据库产品都自带了分区能力,比如:tidb、腾讯 mysql 数据库…将复杂分区能力集成到产品中,大大减少了研发同学工作量。
TDSQL MySQL版 水平分表-产品简介-文档中心-腾讯云
名词解释那节,介绍过 TIDB 分区类型,如何在这些分区类型中选择适合的分区?一切都从业务说起。
所以,我们需要一种按照一定规则(租户 ID),将数据均匀打散到一定数量的分区里面,并且使用上越简单越好。
如果感兴趣可以看看这篇issue,「何时使用 TIDB 分区表」
https://github.com/pingcap/tidb/issues/51628
综上所述,我们采用hash分区,参考链接如下:
TIDB 分区表比较简单,简单介绍案例。
- DROP TABLE IF EXISTS `task`;
- CREATE TABLE `task`
- (
- `id` bigint(255) NOT NULL COMMENT '主键id',
- `tenant_id` bigint(20) NOT NULL COMMENT '租户ID'
- ) ENGINE = InnoDB
- DEFAULT CHARSET = utf8mb4
- COLLATE = utf8mb4_bin
- PARTITION BY HASH (tenant_id)
- PARTITIONS 8;
PARTITIONS 指定分区数量为 8,不指定默认为1;指定分区键为 tenant_id。
通过下面语句查看分区信息SHOW TABLE REGIONS | PingCAP 文档中心
- SHOW TABLE task REGIONS;
- SHOW CREATE TABLE task;
插入数据
INSERT INTO task VALUES (1,2),(100,2),(200,3);
看执行计划
explain analyze select * from task;
对分区表数据操作必须带分区键,否则,全分区扫数据。
创建分区表是按租户 ID分区,where 条件一定要带租户 ID 才能命中所在分区,修改 SQL 如下:
- explain analyze
- select *
- from task
- where tenant_id = 2
- and id = 1;
看执行计划
命中 P2 分区,因为没有建索引,所以在 P2 分区全表扫描,扫描范围缩小了。
单表--> 分区表,N亿+的数据怎么同步到分区表呢?
因为本次梳理模型有些字段被冗余在新表,数据同步不单是A表到B表,需要从其它表查询数据在写入,我们常用的方案是 oplog、binlog.... 日志采集同步到消息队列(kafka、pulsar 等),启消费组消费订正数据(我最常用也是最可靠的),数据量大的场景特别爽,处理存量数据的同时还能保证增量数据同步处理。这方案也有几个问题需要注意。
相比亿级别表优化 SQL 篇,本文重点介绍模型优化和分区表。当然,分区表并不是最终方案,随着数据量不断增加,架构会继续演进,如果对亿级别优化感兴趣请关注我哦。
下篇介绍亿级表优化之数据冷热分离。
下面回答下遗留问题,冗余字段如果数据修改后数据更新怎么办?一般冗余字段前提是不频繁被修改的(尤其是大表频繁修改肯定会有稳定性问题),甚至还有更严格的为不会变数据做字段冗余。另外,早期我们冗余字段出现过大批量更新问题,一般这种慢SQL都在20s以上,如果索引优化不好扫描行数几百万都常见。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。