mysql分库分表分片分区及常见问题

文章探讨了MySQL在数据量增大后的性能下降问题,提出了分库、分表、分区和分片等策略来提升数据库的读写性能。分库旨在降低单库数据量,分表包括垂直和水平划分,以减少单表数据量和IO压力。分区是将数据文件按规则切割,而分片则涉及多库多表的分布。此外,文章强调了监控数据库状态、优化SQL和设置合适的连接池大小的重要性,因为慢SQL可能导致连接池耗尽和其他问题。

1.前言

MySQL单库数据量在5000万以内性能比较好,超过阈值后性能会随着数据量的增大而变弱。MySQL单表的数据量是500w-1000w之间性能比较好,超过1000w性能也会下降。

2.mysql分布式

  1. 分库

分库一般有两种目的:将库中不同表进行拆分,将库中某个表进行拆分,目标就是降低单库的数据量,从而提高io能力和并发能力。

将不同表拆分即将不同的大表移动到其他库中,缓解单库压力,通过多数据源即可进行切换查询,成本最低。

将相同表进行拆分,需要根据某种规则进行拆分,比如按照时间、按照某个主键,这种方式既进行了分表也进行了分库,属于分片的范畴。

  1. 分表

分表分为垂直划分和水平划分。

垂直划分即将不同的字段进行拆分。比如一个学生表中,含有年龄、班级、成绩等属性。我们可以将其拆分为学生、年龄表和学生、成绩表,防止某个属性过大,造成单表的数据量不大,但占用空间极大,造成io缓慢。

水平划分即可通过主键区间划分,或者主键取模或者位运算。这些方式均是将数据水平拆分,每个表的数据结构都是一样的,将数据打散到多个表中,降低单表的数据量,提高能力。

  1. 分区

mysql提供的一种能力。首先 mysql的文件分为三个,具体名字不做阐述,分别为存储表结构、存储数据文件、存储索引数据。分区时,可按照list、hash、区间等多个方式进行分区,将这存储数据的两个文件打散,根据以上的规则分为多个文件。实际仍处于同一个库同一个表中,只是文件切割开,不同的分区文件可以存储咋不同的磁盘上,不允许跨DB。

  1. 分片

分片是将表中数据按照某种规则放到多个库中,既分表又分库,就相当于原先一个库中的一个表,现在放到了好多个表里面,然后这好多个表又分散到了好多个库中。它可以提高 MySQL 数据库的读写性能,特别是在读多写少的情况下。

image.png

以上是数据库方面的性能增强,总结以上为,单库单表存在性能瓶颈,我们首先突破单表,接着突破单库,突破单机器,将磁盘更换为ssd,增强读写性能。数据库的性能一部分在于自身的局限性,一部分在于硬件的性能。

日常开发中,我们也需要对数据库进行监控,查看cpu数值、硬盘使用率等,监控慢sql,监控数据库连接数。

总结历史问题如下:

1.之前出现过多次,因慢sql导致数据库连接池被打满导致后续无连接问题。

2.也出现过,因多个系统同时连接一个库,导致连接数暴增。

3.亦出现过,因调整服务读写分离,使用不同数据源时,未配置新插件的数据库连接池大小,导致连接数过小,请求数一多,就将数据库链接打满,导致无法响应了。所以设置好服务的数据库连接池数也是重中之重。

4.事务开启过大,导致死锁、回滚时间长、易发生异常回滚、数据库连接池占满、接口性能差

5.通过非索引字段进行更新操作,导致间隙锁的发生,最终死锁。

6.事务中,开启分布式锁,事务结束前,解锁,导致并发问题。

7.查询sql中未对空值进行校验,导致查询全表数据,直接oom

8.查询sql未命中索引,导致查询语句过慢,连接池被打满。

总结以上,慢sql致命。

### MySQL 分库分表实现方法 #### 1. 水平拆分 (Sharding) 水平拆分是指按照一定的规则将数据分布到多个物理存储单元中。通常基于某些字段(如 `user_id` 或者 `order_id`),通过哈希算法或其他逻辑函数计算出具体的分片位置。 - **优点**: 可以有效缓解单一数据库的压力,支持海量数据存储;适合读多写的场景。 - **缺点**: 失去了全局索引的支持,增加了开发复杂度,尤其是涉及到跨库操作时更为明显[^4]。 ```sql CREATE TABLE user_order_shard_0 ( order_id BIGINT NOT NULL, user_id INT NOT NULL, ... ); CREATE TABLE user_order_shard_1 ( order_id BIGINT NOT NULL, user_id INT NOT NULL, ... ); ``` #### 2. 垂直拆分 (Vertical Splitting) 垂直拆分则是指根据不同业务需求对原始大宽表进行切割成若干个小窄表的过程。每张新创建的小表只保留原表中的部分列,并且这些子表之间可能存在外键关联关系。 - **优点**: 减少了每次查询返回的数据量,提高了缓存命中率;简化了应用程序的设计模型。 - **缺点**: 需要修改原有的SQL语句和程序逻辑,维护成本较高。 ```sql -- 用户基本信息表 CREATE TABLE user_basic_info( user_id INT PRIMARY KEY, name VARCHAR(50), age TINYINT UNSIGNED ); -- 用户扩展信息表 CREATE TABLE user_extra_info( user_id INT PRIMARY KEY, address TEXT, phone_number CHAR(11) ); ``` --- ### 跨分库查询问题解决方案 当面对跨分库查询的需求时,由于各分库间相互独立,传统的JOIN操作变得不再适用。以下是几种常见的解决策略: #### 使用中间件代理层 借助于成熟的分布式数据库中间件工具,可以在不改动现有应用的前提下透明化地处理复杂的跨库查询请求。这类软件会解析传入的SQL命令并将其转换为针对各个实际存在的分区执行的具体指令集,最终汇总结果反馈给客户端。 例如:MyCat、Atlas等开源项目提供了良好的兼容性和易用性接口,允许开发者轻松构建起高效的微服务体系架构下的持久层组件[^1]。 #### 数据冗余复制机制 为了满足特定报表统计类应用场景的要求,有时会选择定期同步重要维度的信息至集中式的汇总表格内。尽管这可能会占用额外的空间资源,但却能极大程度上优化实时分析任务的速度表现。 ```sql INSERT INTO global_user_summary SELECT * FROM shard_db.user_table WHERE update_time >= DATE_SUB(CURDATE(), INTERVAL 7 DAY); ``` #### 应用级聚合处理 对于那些无法直接利用上述两种途径的情况,则建议采用编程的方式,在服务端手动收集来自不同源的结果集合后再做进一步加工整理工作。虽然这样做无疑增加了编码难度和技术栈依赖项的数量,但在灵活性方面却有着无可比拟的优势。 ```java List<UserOrder> ordersFromDbA = queryOrdersByUserIdInDatabaseA(userId); List<ProductInfo> productsFromDbB = fetchProductsByIds(getProductIdsFromOrders(ordersFromDbA)); assembleResultForClientSideDisplay(ordersFromDbA, productsFromDbB); ``` --
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值