MySQL中大量数据优化方案

2023-10-23  本文已影响0人  上善若泪

1 大量数据优化

1.1 引言

当我们业务数据库表中的数据越来越多,如果你也和我遇到了以下类似场景,那让我们一起来解决这个问题:

1.2 评估表数据体量

我们可以从表容量/磁盘空间/实例容量三方面评估数据体量,接下来让我们分别展开来看看

1.2.1 表容量

表容量主要从表的记录数、平均长度、增长量、读写量、总大小量进行评估。一般对于OLTP的表,建议单表不要超过2000W行数据量,总大小15G以内。访问量:单表读写量在1600/s以内

查询行数据的方式:我们一般查询表数据有多少数据时用到的经典sql语句如下:

但是当数据量过大的时候,这样的查询就可能会超时,所以我们要换一种查询方式

上述方法不仅可以查询表的数据,还可以输出表的详细信息 , 加 \G 可以格式化输出。包括表名 存储引擎 版本 行数 每行的字节数等等

1.2.2 磁盘空间

查看指定数据库容量大小

select
table_schema as '数据库',
table_name as '表名',
table_rows as '记录数',
truncate(data_length/1024/1024, 2) as '数据容量(MB)',
truncate(index_length/1024/1024, 2) as '索引容量(MB)'
from information_schema.tables
order by data_length desc, index_length desc;

查询单个库中所有表磁盘占用大小

select
table_schema as '数据库',
table_name as '表名',
table_rows as '记录数',
truncate(data_length/1024/1024, 2) as '数据容量(MB)',
truncate(index_length/1024/1024, 2) as '索引容量(MB)'
from information_schema.tables
where table_schema='mysql'
order by data_length desc, index_length desc;

查询出的结果如下:


image.png

建议数据量占磁盘使用率的70%以内。同时,对于一些数据增长较快,可以考虑使用大的慢盘进行数据归档

1.2.3 实例容量

MySQL是基于线程的服务模型,因此在一些并发较高的场景下,单实例并不能充分利用服务器的CPU资源,吞吐量反而会卡在mysql层,可以根据业务考虑自己的实例模式

1.3 出现问题的原因

上面我们已经查到我们数据表的体量了 那么为什么单表数据量越大 业务的执行效率就越慢 根本原因是什么呢?

点击了解 MySQL 一棵B+树可以存多少数据量

1.4 解决问题

这里提供了三种解决方案,包括数据表分区,分库分表,冷热数据归档 了解完这些方案之后大家可以选取适合自己业务的方案

1.4.1 数据表分区

1.4.1.1 简介

表分区可以在区间内查询对应的数据,降低查询范围 并且索引分区也可以进一步提高命中率,提升查询效率
分区是指将一个表的数据按照条件分布到不同的文件上面,未分区前都是存放在一个文件上面的,但是它还是指向的同一张表,只是把数据分散到了不同文件而已。

1.4.1.2 优缺点

表分区有什么好处?

表分区的限制因素:

1.4.1.2 操作

在进行分区之前可以用如下方法 看下数据库表是否支持分区

mysql> show variables like '%partition%';
+-------------------+-------+
| Variable_name     | Value |
+-------------------+-------+
| have_partitioning | YES   |
+-------------------+-------+
1 row in set (0.00 sec)

建表分区

CREATE TABLE test_table (
    id INT,
    name VARCHAR(50),
    created_at DATETIME
)
PARTITION BY RANGE (YEAR(created_at))
(
    PARTITION p0 VALUES LESS THAN (2020),
    PARTITION p1 VALUES LESS THAN (2021),
    PARTITION p2 VALUES LESS THAN (2022),
    ...
    PARTITION pn VALUES LESS THAN MAXVALUE
);

建索引分区
创建分区索引的语法与创建普通索引类似。我们可以在创建表时同时创建分区索引,也可以在创建表后单独创建分区索引
在建表时建立索引分区

-- 在创建表时创建分区索引
CREATE TABLE orders (
    id INT,
    order_date DATE,
    amount DECIMAL(10, 2),
    INDEX idx_order_date (order_date)
)
PARTITION BY RANGE (YEAR(order_date)) (
    PARTITION p2018 VALUES LESS THAN (2019),
    PARTITION p2019 VALUES LESS THAN (2020),
    PARTITION p2020 VALUES LESS THAN (2021),
    PARTITION p2021 VALUES LESS THAN (2022)
);
-- 创建表后单独创建分区索引
ALTER TABLE orders ADD INDEX idx_order_date (order_date) LOCAL;

在建表后建立索引分区

-- 建立索引分区
ALTER TABLE your_table
PARTITION BY RANGE (YEAR(created_at))
(
 PARTITION p0 VALUES LESS THAN (2020),
 PARTITION p1 VALUES LESS THAN (2021),
 PARTITION p2 VALUES LESS THAN (2022),
 ...
 PARTITION pn VALUES LESS THAN MAXVALUE
)
PARTITION BY KEY(id) PARTITIONS 4;

查询时可以添加分区,也可以不添加分区

SELECT * FROM t_order PARTITION (p0);
或者
SELECT * FROM t_order

1.4.2 数据库分表

1.4.2.1 简介

分表后,显而易见,单表数据量降低,树的高度变低,查询经历的磁盘io变少,则可以提高效率
分库分表就是为了解决由于数据量过大而导致数据库性能降低的问题,将原来独立的数据库拆分成若干数据库组成 ,将数据大表拆分成若干数据表组成,使得单一数据库、单一数据表的数据量变小,从而达到提升数据库性能的目的。

mysql 分表分为两种:水平分表垂直分表

知道了两个知识后,我们来看一下分库分表的方案

1.4.2.2 分库分表方案

1.4.2.2.1 取模方案

拆分之前,先预估一下数据量。比如用户表有4000w数据,现在要把这些数据分到4个表user1 user2 uesr3 user4。比如id = 17,17对4取模为1,加上 ,所以这条数据存到user2表。
注意:进行水平拆分后的表要去掉auto_increment自增长。这时候的id可以用一个id 自增长临时表获得,或者使用 redis incr的方法。

image.png

优点:数据均匀的分到各个表中,出现热点问题的概率很低。
缺点:以后的数据扩容迁移比较困难难,当数据量变大之后,以前分到4个表现在要分到8个表,取模的值就变了,需要重新进行数据迁移。
点击了解 数据库之Sharding分库分表操作详解

1.4.2.2.2 range 范围方案

以范围进行拆分数据,就是在某个范围内的订单,存放到某个表中。比如id=12存放到user1表,id=1300万的存放到user2 表。


image.png

优点:有利于将来对数据的扩容
缺点:如果热点数据都存在一个表中,则压力都在一个表中,其他表没有压力。
我们看到以上两种方案 都存在缺点 但是却又是互补的,那么我们将这两个方案结合会怎样呢

1.4.2.2.3 hash取模和range方案结合

如下图 我们可以看到 group 组存放id 为 0~4000万 的数据,然后有三个数据库 DB0 DB1 DB2,DB0里面有四个数据库,DB1 和DB2 有三个数据库

假如id为15000 然后对10取模(为啥对10 取模 因为有10个表),取0 然后 落在DB_0,然后在根据range 范围,落在Table_0 里面。


image.png

总结:采用 hash 取模和 range 方案结合 既可以避免热点数据的问题,也有利于将来对数据的扩容

1.4.2.3 分区分表区别

分区分表区别:

1.4.2.4 分区分表的联系

1.4.2.5 分库分表存在的问题

1.4.3 冷热归档

1.4.3.1 简介

为什么要冷热归档:其实原因和方案二类似,都是降低单表数据量,树的高度变低,查询经历的磁盘io变少,则可以提高效率 如果大家的业务数据,有明显的冷热区分,比如:只需要展示近一周或一个月的数据。那么这种情况这一周和一个月的数据我们称之为热数据,其余数据为冷数据。那么我们可以将冷数据归档在其他的库表中,提高我们热数据的操作效率。

1.4.3.2 操作

创建归档表 创建的归档表 原则上要与原表保持一致
归档表数据的初始化


image.png

业务增量数据处理过程


image.png

数据的获取过程


image.png

1.5 实际选择

方案 试用场景 优点 缺点
数据表分区 1.数据量较大 2.查询场景只在某个区 3.没有联合查询的场景 分区分表是在物理上对数据表所对应的文件进行拆分,对应的表名是不变的,所以不会影响到之前业务逻辑的sql 分表后的查询等业务会创建对应的对象,也会造成一定的开销分区数据若要聚合的话 耗费时间也较长;使用范围不适合数据量千万级以上的
数据表分表 数据量较大,无法区分明显冷热区 且数据可以完整按照区间划分 适用于对冷热分区的界限不是很明显的数据,对后续类似的数据可以采用该方式,将大表拆分成小表 提高查询插入等效率 若大数据表逐渐增多 那么对应的数据库表越来越多 每个表都需要分表; 区间的划分较为固定若后续单表的数据量大起来 也会对性能造成影响;实现复杂度相对方案三比较复杂 需要测试整人实现过程 在编码层处理 对原有业务有影影响
冷热归档分库 数据量较大;数据冷热分区明显;冷数据使用频率极低; 数据迁移的过程对业务的影影响较小 开发量也较少减少成本 需要确认分表规则
上一篇下一篇

猜你喜欢

热点阅读