百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

MySQL分区表简介(mysql分区表使用场景)

wxin55 2024-11-14 18:42 10 浏览 0 评论

一、背景

我们的业务只存近一段时间的数据,因此有大量表需要清理历史数据,目前使用的delete清理数据,存在以下问题。为避免同时支持大量delete,我们的清理任务只在低峰期串行执行,导致任务过多时需要排队,甚至失败的情况;数据清理使用delete语句,表数据量较大时,对数据库造成很大压力;即使我们删除了旧数据,已删除的数据仍占据存储空间,底层数据文件并没有立刻变小,以至于形成数据空洞。

查看MySQL官方文档时,发现了分区表,因此基于官方文档总结一下。

二、什么是分区表?

MySQL逻辑上为一个表,物理上存储在多个文件中,这是 MySQL 支持的功能(5.1 开始), 8.0 版本只 InnoDB 和 NDB 支持分区表。

三、分区表有啥优缺点?

优点:

  • 和单个磁盘或文件系统分区相比,可以存储更多的数据。
  • 优化查询:
  • where 子句中包含分区条件时,可以直接扫描必要的分区。
  • 涉及聚合函数的查询时,可以很容易地在每个分区上并行处理,最终只需汇总得到结果。
  • 对于已经过期或者不需要保存的数据,可以通过删除与这些数据有关的分区来快速删除数据。
  • 跨多个磁盘来分散数据查询,以获得更大的查询吞吐量。

缺点:

  • 新建、删除分区操作的时候,会获取表的MDL锁,这是一把全局锁,可能会对业务产生慢查的影响;
  • 分区表在执行alter语句时,比如增加、删除分区,更容易出现MDL锁冲突,引起慢查等情况;
  • InnoDB分区表不支持外键

四、分区类型

4.1 Range 分区

根据分区表键值的范围把数据存储到表的不同分区中,适用于以时间或日期作为分区类型,方便数据清理。

CREATE TABLE employees (     
  id INT NOT NULL,     
  fname VARCHAR(30),     
  lname VARCHAR(30),     
  hired DATE NOT NULL DEFAULT '1970-01-01',     
  separated DATE NOT NULL DEFAULT '9999-12-31',     
  job_code INT NOT NULL,     
  store_id INT NOT NULL ) 
  PARTITION BY RANGE (store_id) (     
    PARTITION p0 VALUES LESS THAN (6),     
    PARTITION p1 VALUES LESS THAN (11),     
    PARTITION p2 VALUES LESS THAN (16),     
    PARTITION p3 VALUES LESS THAN (21) 
  ); 
-- 使用函数将日期转换 
CREATE TABLE employees_1 (     
  id INT NOT NULL,     
  fname VARCHAR(30),     
  lname VARCHAR(30),     
  hired DATE NOT NULL DEFAULT '1970-01-01',     
  separated DATE NOT NULL DEFAULT '9999-12-31',     
  job_code INT NOT NULL,     
  store_id INT NOT NULL ) 
  PARTITION BY RANGE (year(hired)) (     
    PARTITION p0 VALUES LESS THAN (6),     
    PARTITION p1 VALUES LESS THAN (11),     
    PARTITION p2 VALUES LESS THAN (16),     
    PARTITION p3 VALUES LESS THAN (21) ); 
-- 使用date 或 datetime 例作为分区例时 可使用 RANGE COLUMNS 对表进行分区 
CREATE TABLE employees_2 (     
  id INT NOT NULL,     
  fname VARCHAR(30),     
  lname VARCHAR(30),     
  hired DATE NOT NULL DEFAULT '1970-01-01',     
  separated DATE NOT NULL DEFAULT '9999-12-31',     
  job_code INT NOT NULL,     
  store_id INT NOT NULL ) 
  PARTITION BY RANGE COLUMNS (hired) (     
    PARTITION p0 VALUES LESS THAN ('1970-01-01'),     
    PARTITION p1 VALUES LESS THAN ('1971-01-01'),     
    PARTITION p2 VALUES LESS THAN ('1972-01-01'),     
    PARTITION p3 VALUES LESS THAN ('1973-01-01') 
  );

小提示:

1.当插入数据分区不存在时会报错:Table has no partition for value xxx;

2.Range类型分区字段必须是数值,时间类型可用函数转换为数值;

3.分区字段列值可以为null,所有为null的数据将存在最小的分区中;

4.2 List分区

按分区键取值的列表进行分区,每一行数据须找到对应的分区列表,否则数据插入失败

CREATE TABLE employees (     
    id INT NOT NULL,     
    fname VARCHAR(30),     
    lname VARCHAR(30),     
    hired DATE NOT NULL DEFAULT '1970-01-01',     
    separated DATE NOT NULL DEFAULT '9999-12-31',     
    job_code INT,     
    store_id INT ) 
    PARTITION BY LIST(store_id) (     
    PARTITION pNorth VALUES IN (3,5,6,9,17),     
    PARTITION pEast VALUES IN (1,2,10,11,19,20),     
    PARTITION pWest VALUES IN (4,12,13,14,18),    
    PARTITION pCentral VALUES IN (7,8,15,16)
);

小提示:

  1. List分区表不存在 MAXVALUE 之类的,所以在设计时一定要全面评估,否则分区不存在时写入会报错;
  2. 可以显示指定一个null分区,eg: pxx values in (null);
  3. 如果没有指定null分区时,分区字段值为null会报错:Table has no partition for value NULL;

4.3 Hash分区

根据指定分区表达式的整数值以及分区数进行数据划分(mod函数)

CREATE TABLE employees_hash (     
  id INT NOT NULL,     
  fname VARCHAR(30),     
  lname VARCHAR(30),     
  hired DATE NOT NULL DEFAULT '1970-01-01',     
  separated DATE NOT NULL DEFAULT '9999-12-31',     
  job_code INT,     store_id INT ) 
  PARTITION BY HASH(store_id) PARTITIONS 4;

小提示:

  1. 当分区表达式输出为null时,被当做0处理;

4.4 Key分区

按键分区类似于按哈希分区,只是哈希分区使用用户定义的表达式,用于键分区的哈希函数由 MySQL 服务器提供。NDB 集群为此使用 MD5() ; 对于使用其他存储引擎的表,服务器使用自己的内部哈希函数。

CREATE TABLE k1 (     
  id INT NOT NULL,     
  name VARCHAR(20),     
  UNIQUE KEY (id) ) 
  PARTITION BY KEY() PARTITIONS 2;

小提示:

  1. 分区字段不填写时,可以不填写分区字段,优先使用主键作为分区字段,其次是唯一键;没有主键或唯一键时,分区字段必填
  2. 分区字段可以是非整数或null值;
  3. 当分区表达式输出为null时,被当做0处理;

4.3 子分区

子分区(subpartitioning)也称为复合分区(composite partitioning) ,是已分区表中每个分区的进一步划分

CREATE TABLE ts (
  id INT, 
  purchased DATE)     
  PARTITION BY RANGE( YEAR(purchased) )    
  SUBPARTITION BY HASH( TO_DAYS(purchased) )     
  SUBPARTITIONS 2 (         
    PARTITION p0 VALUES LESS THAN (1990),         
    PARTITION p1 VALUES LESS THAN (2000),         
    PARTITION p2 VALUES LESS THAN MAXVALUE    
  );

小提示:

  1. 每个分区必须具有相同数量的子分区;

五、分区管理

5.1 Range 和 List

-- 增加分区 
alter table employees_list add partition (partition pxx values in (null));  ALTER TABLE tt ADD PARTITION (PARTITION p2 VALUES IN (7, 14, 21)); 
-- 删除分区 
ALTER TABLE employees_list DROP PARTITION pxx; 
-- 将一个分区分为多个分区 
ALTER TABLE employees_3  REORGANIZE PARTITION employees_list INTO (         
  PARTITION n0 VALUES LESS THAN (1970), 
PARTITION n1 VALUES LESS THAN (1980) ); 
-- 清空分区
ALTER TABLE employees_3 TRUNCATE PARTITION pxx; 

5.2 Hash 和 Key分区

-- 缩减n个分区 
ALTER TABLE employees_hash COALESCE PARTITION 4; 
-- 增加n个分区 
ALTER TABLE employees_hash ADD PARTITION PARTITIONS 6;

小提示:

  1. 使用COALESCE 减少分区数时,不能减少至0;

六、指定分区查询

-- 可以指定分区号或以分区字段作为条件 
select * from employees_hired PARTITION (p2021) 
where store_id = 551 and hired >= '2020-12-31' and hired <= '2021-01-01'

七、分区表注意事项

  1. PRIMARY KEY、UNIQUE KEY 必须包含分区字段;
  2. 分区表达式支持函数,但不是所有函数都支持,存储过程、存储函数、可加载函数和插件都不支持,算术运算符支持 +、- 、* 、div,不支持"/",位运算也不支持;
  3. MySQL 8.0 仅InnoDB和NDB支持分区表,其他engine不支持;
  4. range 分区中,null 值会被当作最小值来处理;
  5. list 分区中,null 值必须出现在枚举列表中,否则不被接受;
  6. hash/key 分区中,null 值会被当作零值来处理。

相关推荐

ES6中 Promise的使用场景?(es6promise用法例子)

一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...

JavaScript 对 Promise 并发的处理方法

Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...

Promise的九大方法(promise的实例方法)

1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...

360前端一面~面试题解析(360前端开发面试题)

1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...

前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?

Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...

最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式

看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...

前端分享-Promise可以中途取消啦(promise可以取消吗)

传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...

手写 Promise(手写输入法 中文)

前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...

什么是 Promise.allSettled()!新手老手都要会?

Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...

前端面试-关于Promise解析与高频面试题示范

Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...

宇宙厂:为什么前端离不开 Promise.withResolvers() ?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...

Promise 新增了一个超实用的 API!

在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...

一次搞懂 Promise 异步处理(promise 异步顺序执行)

PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...

Promise 核心机制详解(promise机制的实现原理)

一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...

javascript——Promise(js实现promise)

1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...

取消回复欢迎 发表评论: