亿级表优化「TIDB 分区篇」,值得收藏

news2024/11/28 4:28:53

这是亿级别表优化的第二篇,对第一篇感兴趣的可以看看。

亿级表优化思路之SQL篇 - 掘金

写作背景

距上次写亿级别优化已经有一个多月了,这段时间也没闲着,Q1 对模型做了梳理,重构了这部分业务,主要做了下面这些优化

  1. 数据模型优化(终于狠下心做了减法,去掉了 2 个模型)。
  2. 做了分区表,数据日增量非常快,单表遇到读写瓶颈。
  3. 复杂 SQL 优化,上次优化遗留的顽疾。
  4. 数据清洗(流失数据、已删除数据备份归档)。

所以,我还是总结这段时间成果吧!分享这次优化的经验。

距离上次数据量统计,数据已经增长了 2000W。

名词解释

垂直分库

垂直分库是指根据业务来分库,不同的业务使用不同的数据库。例如,营销自动化业务和营销活动都存在高并发场景,如果使用同一个库,会占用一定的连接数,所以我们可以将数据库分为营销自动化库和营销活动库。在一些特定情况下我们还会分集群,不同业务模块使用不同集群。

垂直分表

垂直分表则是指把一张表中的字段,拆分为多张表(我习惯性称为子表或者附表)将数据散落在多张表内,一开始将一些不经常使用的字段拆分到另一张表中,亦或是在迭代过程中扩展子表来满足需求(迭代中扩展子表的方式在之前版本中前尝试过,扩展了好几张表最后都合并了,随着业务需求增加,数据查询越来越复杂,最后舍弃了这种方式)。

水平分表

水平切分(分表)是按照某种规则,将一个表的数据分散到多个物理独立的数据库服务器中,形成“独立”的数据库“分片”。一般是按照 Range 或 Hash 取模。

TIDB 分区表

Table Partition 是指根据一定规则,将数据库中的一张表分解成多个更小的容易管理的部分。从逻辑上看只有一张表,但是底层却是由多个物理分区组成。

在 TiDB 中分区表是一个独立的逻辑表,但是底层由多个物理子表组成。物理子表其实就是普通的表,数据按照一定的规则划分到不同的物理子表类内。程序读写的时候操作的还是逻辑表名字,TiDB 服务器自动去操作分区的数据。

想了解更多参考以下文档

TiDB 源码阅读系列文章(二十)Table Partition | PingCAP

TIDB 支持的分区类型

Range 分区、Range COLUMNS 分区、Range INTERVAL 分区、List 分区、List COLUMNS 分区、Hash 分区、Key 分区。想了解更多语法和案例参考以下文档

分区表 | PingCAP 文档中心

优化思路

模型整合

早期对业务未来发展判断不准确以及过度设计,认为每个数据模型都应该满足数据库三范式,但付出的代价也非常高昂。

  1. 某些业务需要多次数据库 IO ,否则用 join,开发比较麻烦,另外,性能也不高;
  2. 有几张表数据量比较大,维护成本高;
  3. 另外,模型 a 跟模型 b 是一对多关系,模型 a 数据写入存在并发问题,不得不牺牲并发能力,注:不使用分布式锁,用消息队列,根据某一个业务标志把一类数据打到同一个分区,tob 行业,某些大租户数据倾斜是比较严重的…

这次梳理模型的原则是比较简单的。

  1. 数据模型是否满足未来 1-2 年的迭代,有一个模型因为产品规划需要支持多平台,我们重命名了表名字和字段名,更符合未来的产品方向。
  2. 去掉数据模型,是否影响产品逻辑,有2个模型因为第一版过度设计+业务不清晰,最后导致查询逻辑和模型维护复杂,再加上产品和技术不断演进有更好的解决方案,及时把模型优化了。
  3. 字段冗余,把该冗余字段冗余出来,后续分区表避免 Join 连表查询。这里有一问题大家可以思考下,数据冗余后,如果数据修改后数据更新怎么办?文章末尾给答案。

分区表

什么时候用分库分表?

在单表单库下,当数据表的数据量逐渐累积到一定的数量时,操作数据库的性能会出现明显下降,即使我们使用索引优化,性能依然会存在瓶颈。如果每日数据增长大,我们应该考虑分表。

面对大量数据,除了单表的性能比较差以外,数据库连接数、磁盘 I/O 以及网络吞吐等资源都是有限的,并发能力也是有限的。所以,在一些大数据量且高并发的业务场景中,也需要考虑分表分库来提升数据库的并发处理能力。

如何分库分表?

分库分表业界方案都是很成熟的,有两种方案,垂直切分和水平切分两种。名词解释那节已经解释过了,这里不过多解释。

分库分表依赖数据库中间件,但是,某些数据库产品都自带了分区能力,比如:tidb、腾讯 mysql 数据库…将复杂分区能力集成到产品中,大大减少了研发同学工作量。

TDSQL MySQL版 水平分表-产品简介-文档中心-腾讯云

名词解释那节,介绍过 TIDB 分区类型,如何在这些分区类型中选择适合的分区?一切都从业务说起。

  1. 营销自动化业务主要是给员工下发任务,员工侧要展示任务,所以是按照租户 ID+员工 ID 纬度聚合数据;
  2. 公司管理者需要看当前公司下所有员工任务完成情况,所以是按照租户 ID 纬度聚合数据,并且聚合这些数据跟时间无关。

所以,我们需要一种按照一定规则(租户 ID),将数据均匀打散到一定数量的分区里面,并且使用上越简单越好。

如果感兴趣可以看看这篇issue,「何时使用 TIDB 分区表」

https://github.com/pingcap/tidb/issues/51628

综上所述,我们采用hash分区,参考链接如下:

分区表 | PingCAP 文档中心

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 分区全表扫描,扫描范围缩小了。

SQL 优化

  1. 复杂数据分析业务迁移 OLAP 数据库
    报表类业务迁移 Doris,这类业务不适合放在 TIDB。我们刚好有一场景是管理端列表页面需要聚合报表类数据(很早就想优化,但迟迟未动手),SQL 比较复杂索引调优不好做,这类 SQL qps 一上去整张表的延迟绝对增加。另外,为了这条 sql 加了一条索引。
  2. 缩小 SQL 扫描范围
    我们有一平台性调度任务,扫全表更改数据状态,每次更新 5000,循环更新。每次活动期间这条 SQL 肯定会被运维拉出来批斗。优化策略比较简单,调度任务细化,按照某一 id 创建调度任务,把调度打散在不同时间段,避免数据集中在同一时刻被处理。

数据清洗

单表--> 分区表,N亿+的数据怎么同步到分区表呢?

因为本次梳理模型有些字段被冗余在新表,数据同步不单是A表到B表,需要从其它表查询数据在写入,我们常用的方案是 oplog、binlog.... 日志采集同步到消息队列(kafka、pulsar 等),启消费组消费订正数据(我最常用也是最可靠的),数据量大的场景特别爽,处理存量数据的同时还能保证增量数据同步处理。这方案也有几个问题需要注意。

  1. 如果数据量大,查询时控制并发、另外攒批查询,避免高峰期数据库 QPS 高造成稳定性问题。
  2. 查询业务方接口加上缓存,避免流量高打垮业务方系统。
  3. 数据订正支持重复操作,若中途中断,亦或订正代码有 bug 造成整数据订正中断,也可重跑数据,或断点续跑数据。
  4. 数据订正支持按照某一个规则订正,比如按租户 id,通过一批租户验证线上订正脚本正确性。

末尾彩蛋

相比亿级别表优化 SQL 篇,本文重点介绍模型优化和分区表。当然,分区表并不是最终方案,随着数据量不断增加,架构会继续演进,如果对亿级别优化感兴趣请关注我哦。

下篇介绍亿级表优化之数据冷热分离。

下面回答下遗留问题,冗余字段如果数据修改后数据更新怎么办?一般冗余字段前提是不频繁被修改的(尤其是大表频繁修改肯定会有稳定性问题),甚至还有更严格的为不会变数据做字段冗余。另外,早期我们冗余字段出现过大批量更新问题,一般这种慢SQL都在20s以上,如果索引优化不好扫描行数几百万都常见。

参考文献

TiDB 源码阅读系列文章(二十)Table Partition | PingCAP

分区表 | PingCAP 文档中心分区表 | PingCAP 文档中心分区表 | PingCAP 文档中心

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1581952.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大厂面试:找出数组中第k大的数的最佳算法

一.前置条件 假如数组为a,大小为n,要找到数组a中第k大的数。 二.解决方案 1.使用任意一种排序算法(例如快速排序)将数组a进行从大到小的排序,则第n-k个数即为答案。 2.构造一个长度为k的数组,将前k个数复制过来并降序…

笔记:[dv-admin开发系列]--2.0版本环境搭建

目录 来源新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公…

基于51单片机的病床呼叫系统设计与实现Proteus仿真

地址:https://pan.baidu.com/s/1bybQ0wc-FNtkemkFvGotsA 提取码:1234 仿真图: 利用矩阵键盘、蜂鸣器和数码管搭建一个小型病床呼叫系统。用16个按键模拟16个病床的呼叫按钮,当有按键按下时,护士站处由蜂鸣器发出报警声…

广告投放分析

项目背景 Facebook被众多企业作为首选的广告平台之一,特别是在投放原生广告方面。这个平台允许根据如性别、年龄、地理位置和兴趣等多重标准来细化目标用户群。广告主能够制作专门的Facebook广告,并设定一个特定的“受众群体”,便于他们向某些…

django 4.2 自定义signal的使用方法

环境:win11 python3.9.2 django 4.2.11 背景:执行异步数据存储,想要使用该方法实现(失败了) 时间:20240410 说明:记录一下,避免忘记 1、创建django项目,并实现首页 …

vue点击上传图片并实现图片预览功能,并实现多张图片放到一个数组中进行后端请求(使用原生input)

一、将 File 对象转成 BASE64 字符串 &#xff08;FileReader&#xff09; <template><div><!-- 用来显示封面的图片 --><!-- <img src"/assets/images/cover.jpg" alt"" class"cover-img" ref"imgRef" />…

蓝桥杯嵌入式2023年第十四届省赛主观题解析

1 题目 2 代码 /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "adc.h" #include "rtc.h" #include "tim.h" #include "gpio.h"/* Private includes --…

Leetcode:27.移除元素

题目要求 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外的数组空间&#xff0c;你必须仅使用 O(1) 额外空间并 原地 修改输入数组。 元素的顺序可以改变。你不需要考虑数组中超出…

C语言指针—野指针、指针运算、指针与数组

野指针 指针未初始化 int main(){int *p;//没有初始化&#xff0c;就意味着没有明确的方向//一个局部变量不初始化&#xff0c;放的是随机值:0xCCCCCCCC//请注意&#xff0c;这个地址并不是我们定义的&#xff0c;是一个非法的地址*p 10;//非法访问内存了&#xff0c;这里的…

Unity面经(自整)——移动开发与Shader

Unity与Android混合开发 为什么使用Flutter构建 Flutter 是 Google 的开源工具包&#xff0c;用于从单个代码库为移动、Web、桌面和嵌入式设备构建应用程序&#xff08;一套代码跨平台构建app是它最大的优点&#xff09;&#xff0c;并且可以构建高性能、稳定和丰富UI的应用程…

Spring MVC体系结构和处理请求控制器(一)

一、MVC模式 MVC模式是指Model-View-Controller&#xff08;模型-视图-控制器&#xff09;模式&#xff0c;是开发Web应用程序时常用的一种代码分层模式MVC模式是软件工程中的一种架构模式&#xff0c;会强制行的把系统的输入、处理和输出分开&#xff0c;是系统从功能上形成M…

评论发布完整篇(react版)

此篇文章阐述评论的最新、最热之间的tab标签切换&#xff08;包括当前所在tab标签的高亮显示问题&#xff09;&#xff1b;当前评论的删除&#xff1b;除此之外还延伸了用户的评论实时发布功能。其中最新tab标签所展示的内容是根据当前评论点赞数来进行排序&#xff0c;点赞数量…

数字社会下的智慧公厕:构筑智慧城市的重要组成部分

智慧城市已经成为现代城市发展的趋势&#xff0c;而其中的数字化转型更是推动未来社会治理体系和治理能力现代化的必然要求。在智慧城市建设中&#xff0c;智慧公厕作为一种新形态的信息化公共厕所&#xff0c;扮演着重要角色。本文智慧公厕源头实力厂家广州中期科技有限公司&a…

Go gin框架(详细版)

目录 0. 为什么会有Go 1. 环境搭建 2. 单-请求&&返回-样例 3. RESTful API 3.1 首先什么是RESTful API 3.2 Gin框架支持RESTful API的开发 4. 返回前端代码 go.main index.html 5. 添加静态文件 main.go 改动的地方 index.html 改动的地方 style.css 改动…

C语言 | 字符函数和字符串函数

目录&#xff1a; 1. 字符分类函数 2. 字符转换函数 3. strlen的使用和模拟实现 4. strcpy的使用和模拟实现 5. strcat的使用和模拟实现 6. strcmp的使用和模拟实现 7. strncpy函数的使用 8. strncat函数的使用 9. strncmp函数的使用 10. strstr的使用 11. strtok函…

力扣121. 买卖股票的最佳时机

Problem: 121. 买卖股票的最佳时机 文章目录 题目描述思路复杂度Code 题目描述 思路 1.定义一个int数组max大小同prices&#xff1b;定义int变量curMax初始化为0&#xff1b; 2.从后往前遍历数组&#xff0c;若当前元素prices[i] > curMax时&#xff0c;则使将其赋值给curMa…

医院预约系统微信小程序APP前后端

医院预约系统具体功能介绍&#xff1a;展示信息、可以注册和登录&#xff0c; 预约&#xff08;包含各个科室的预约&#xff0c;可以预约每个各个医生&#xff09;&#xff0c;就诊引导包含预约的具体信息&#xff0c;包含就诊时间、就诊科室、就诊医生以及就诊人信息、和支付状…

如何注册midjourney账号

注册Midjourney账号比较简单&#xff0c;准备好上网工具&#xff0c;进入官网 Midjourney访问地址&#xff1a; https://www.midjourney.com/ 目前没有免费使用额度了&#xff0c;会员最低 10 美元/月&#xff0c;一般建议使用30美元/月的订阅方案。了解如何订阅可以查看订阅…

MyBatis源码介绍

文章目录 MyBatis的核心流程介绍SqlSessionFactory的理解MyBatis中的Executor的源码理解Spring中是如何解决MySQL的SqlSession的线程安全问题MyBatis面向Mapper编程工作原理Mybatis动态sql执行原理Mybatis的一级、二级缓存实现原理Mybatis的插件运行原理以及如何编写一个插件my…

019——IIC模块驱动开发(基于EEPROM【AT24C02】和I.MX6uLL)

目录 一、 IIC基础知识 二、Linux中的IIC&#xff08;韦东山老师的学习笔记&#xff09; 1. I2C驱动程序的层次 2. I2C总线-设备-驱动模型 2.1 i2c_driver 2.2 i2c_client 三、 AT24C02 介绍 四、 AT24C02驱动开发 实验 驱动程序 应用程序 一、 IIC基础知识 总线类…