目录
一、定义
1.1 概述
1.2 分区的优势
二、分区的类型
2.1 检查MySQL是否支持分区
2.2 类型
2.3 分区的其他操作
一、定义
1.1 概述
数据库分区是一种物理数据库设计技术。虽然分区技术可以实现很多效果,但其主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减SQL语句的响应时间,同时对于应用来说分区完全是透明的。
使用myisam引擎的一张表主要对应着三个文件,一个是frm存放表结构的,一个是myd存放表数据的,一个是myi存表索引的。如果一张表的数据量太大的话,那么myd、myi就会变的很大,查找数据就会变的很慢,这个时候我们可以利用mysql的分区功能,在物理上将这一张表对应的三个文件,分割成许多个小块,这样我们查找一条数据时,就不用全部查找了,只要知道这条数据在哪一块,然后在那一块找就行了。如果表的数据太大,可能一个磁盘放不下,我们可以把数据分配到不同的磁盘里面去。
使用innoDB引擎的/mysql/data/数据库名目录下一张表有一个frm文件存放数据结构,其他的数据部分全部都存在在/mysql/data目录下的ibdata文件中。
MYSQL 5.1之后支持分区。
1.2 分区的优势
1)与单个磁盘或文件系统分区相比,可以存储更多的数据。
2)对于不用或者过时的数据很容易给删除掉。
3)对于一些查询有极大的优化,给定WHERE语句的数据可以只保存在一个或多个分区内,这样就不需要查找剩余的数据。
4)涉及到例如SUM()和COUNT()这样聚合函数的查询,可以很容易地进行并行处理。
5)通过跨多个磁盘来分散数据查询,来获得更大的查询吞吐量。
二、分区的类型
2.1 检查MySQL是否支持分区
//查看mysql5.6以下是否支持分区
show variables like '%partition%';
//查看mysql5.6以上是否支持分区
show plugins;
2.2 类型
使用分区的前提:分区键必须是主键的一部分。
解释:分区键必须是主键的一部分并不是 MySQL 的限制,而是索引组织表的限制。之所以对索引组织表有这样的限制,个人认为还是基于性能考虑。假设分区键和主键是两个不同的列,在进行插入操作时,虽然也指定了分区键,但还是需要扫描所有分区才能判断插入的主键值是否违反了唯一性约束。这样的话,效率会比较低下,违背了分区表的初衷。而对于堆表则没有这样的限制,下面是堆表和索引组织表的定义。
堆表:数据存储在表中,索引存储在索引里,两者分开的。数据在堆中是无序的,索引让键值有序,但数据还是无序的。堆表中主键索引和普通索引一样的,都是存放指向堆表中数据的指针。
索引组织表:数据存储在聚簇索引中,或者说,数据按照主键的顺序来组织数据,两者合二为一。主键索引,叶子节点存放整行数据。其他索引称为辅助索引(二级索引),叶子节点存放键值和主键值。
创建表和表数据
CREATE TABLE `user_login_log` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) DEFAULT NULL,
`login_time` int(10) unsigned DEFAULT '0',
`ip` varchar(255) DEFAULT NULL,
`add_time` int(10) unsigned DEFAULT '0',
`up_time` int(10) unsigned DEFAULT '0',
PRIMARY KEY (`id`,`user_id`,`login_time`),
KEY `ip` (`ip`)
) ENGINE=InnoDB AUTO_INCREMENT=1000002 DEFAULT CHARSET=utf8 COMMENT='用户登录日志';
<?php
header('Content-Type:application/json; charset=utf-8');
error_reporting(E_ERROR | E_CORE_ERROR | E_PARSE);
//创建100万条案例数据
function randIp(){
$ipall = array(
array(array(58,14),array(58,25)),
array(array(58,30),array(58,63)),
array(array(58,66),array(58,67)),
array(array(60,200),array(60,204)),
array(array(60,160),array(60,191)),
array(array(60,208),array(60,223)),
array(array(117,48),array(117,51)),
array(array(117,57),array(117,57)),
array(array(121,8),array(121,29)),
array(array(121,192),array(121,199)),
array(array(123,144),array(123,149)),
array(array(124,112),array(124,119)),
array(array(125,64),array(125,98)),
array(array(222,128),array(222,143)),
array(array(222,160),array(222,163)),
array(array(220,248),array(220,252)),
array(array(211,163),array(211,163)),
array(array(210,21),array(210,22)),
array(array(125,32),array(125,47))
);
#随机生成需要IP段
$ip_p = rand(0,count($ipall)-1);
$ip_1 = $ipall[$ip_p][0][0];
if($ipall[$ip_p][0][1] == $ipall[$ip_p][1][1]){
$ip_2 = $ipall[$ip_p][0][1];
}else{
$ip_2 = rand(intval($ipall[$ip_p][0][1]),intval($ipall[$ip_p][1][1]));
}
$ip_3 = rand(0,255);
$ip_4 = rand(0,255);
return $ip_1.'.'.$ip_2.'.'.$ip_3.'.'.$ip_4;
}
$dbcnn = mysqli_connect("127.0.0.1", "root", "root", "db1", "3306");
if (!$dbcnn) {
echo date("Y-m-d H:i:s") . " MySQL connection failed... \n";
exit;
} else {
mysqli_query($dbcnn, "set names utf8");
}
$login_time = ["2022-12-07 08:22:32", "2022-12-07 09:23:32", "2022-12-07 12:13:44", "2022-12-07 09:23:45", "2022-12-07 10:16:32", "2022-12-07 08:21:32", "2022-12-07 09:42:55", "2022-12-07 05:02:25", "2022-12-07 08:23:42", "2022-12-07 11:08:02", "2022-12-07 06:22:33"];
for($i=1001; $i<=1001000; $i++){
mysqli_query($dbcnn, "INSERT INTO `user_login_log` (user_id, login_time, ip, add_time) values({$i}, '".$login_time[array_rand($login_time)]."', '".randIp()."', ".time()." )");
}
1)range分区
按照RANGE分区的表是通过如下一种方式进行分区的,每个分区包含那些分区表达式的值位于一个给定的连续区间内的行。
//添加字段 user_id(复合主键) 的range分区
ALTER table `user_login_log` PARTITION BY RANGE (`user_id`) (
PARTITION p0 VALUES LESS THAN (101000),
PARTITION p1 VALUES LESS THAN (201000),
PARTITION p2 VALUES LESS THAN (301000),
PARTITION p3 VALUES LESS THAN (401000),
PARTITION p4 VALUES LESS THAN (501000),
PARTITION p5 VALUES LESS THAN (601000),
PARTITION p6 VALUES LESS THAN (701000),
PARTITION p7 VALUES LESS THAN (801000),
PARTITION p8 VALUES LESS THAN (901000),
PARTITION p9 VALUES LESS THAN MAXVALUE
);
//查询语句,增加分区前查询耗时 0.976s,增加分区后查询耗时 0.293s,可看到有三倍的增速
select * from `user_login_log` where user_id>=50001 and user_id<=100000;
2)list分区
LIST分区中每个分区的定义和选择是基于某列的值从属于一个值列表集中的一个值,而RANGE分区是从属于一个连续区间值的集合。
//添加字段 login_time(复合主键) 的list分区
ALTER table `user_login_log` PARTITION BY LIST COLUMNS(`login_time`) (
PARTITION p0 VALUES in("2022-12-07 08:22:32", "2022-12-07 09:23:32", "2022-12-07 12:13:44"),
PARTITION p1 VALUES in("2022-12-07 09:23:45", "2022-12-07 10:16:32", "2022-12-07 08:21:32"),
PARTITION p2 VALUES in("2022-12-07 09:42:55", "2022-12-07 05:02:25", "2022-12-07 08:23:42"),
PARTITION p3 VALUES in("2022-12-07 11:08:02", "2022-12-07 06:22:33")
);
//查询语句,增加分区前查询耗时 1.187s,增加分区后查询耗时 0.717s,可看到有 0.47s的增速
select * from `user_login_log` where login_time in("2022-12-07 08:22:32", "2022-12-07 09:23:32", "2022-12-07 12:13:44");
3)hash分区
HASH分区主要用来确保数据在预先确定数目的分区中平均分布,你所要做的只是基于将要被哈希的列值指定一个列值或表达式,以 及指定被分区的表将要被分割成的分区数量。
//添加字段 user_id(复合主键) 的hash分区
ALTER table `user_login_log` PARTITION BY HASH (`user_id`) PARTITIONS 10;
//查询语句,增加分区前查询耗时 0.976s,增加分区后查询耗时 0.518s,可看到有 0.458s的增速
select * from `user_login_log` where user_id>=50001 and user_id<=100000;
4)key分区
按照KEY进行分区类似于按照HASH分区,除了HASH分区使用的用 户定义的表达式,而KEY分区的哈希函数是由MySQL服务器提供。
//添加字段 user_id(复合主键) 的key分区
ALTER table `user_login_log` PARTITION BY HASH (`user_id`) PARTITIONS 10;
//查询语句,增加分区前查询耗时 0.976s,增加分区后查询耗时 0.613s,可看到有 0.363s的增速
select * from `user_login_log` where user_id>=50001 and user_id<=100000;
5)子分区
子分区是分区表中每个分区的再次分割,目前只有RANGE和LIST分区的表可以再进行子分区,子分区只能是HASH或者KEY分区。这也被称为复合分区(composite partitioning)
//添加字段 user_id(复合主键) 的子分区
ALTER table `user_login_log` PARTITION BY RANGE (`user_id`) SUBPARTITION BY HASH (`user_id`)(
PARTITION p0 VALUES LESS THAN (101000) (
SUBPARTITION s0,
SUBPARTITION s1
),
PARTITION p1 VALUES LESS THAN (201000) (
SUBPARTITION s2,
SUBPARTITION s3
),
PARTITION p2 VALUES LESS THAN (301000) (
SUBPARTITION s4,
SUBPARTITION s5
),
PARTITION p3 VALUES LESS THAN (401000) (
SUBPARTITION s6,
SUBPARTITION s7
),
PARTITION p4 VALUES LESS THAN (501000) (
SUBPARTITION s8,
SUBPARTITION s9
),
PARTITION p5 VALUES LESS THAN (601000) (
SUBPARTITION s10,
SUBPARTITION s11
),
PARTITION p6 VALUES LESS THAN (701000) (
SUBPARTITION s12,
SUBPARTITION s13
),
PARTITION p7 VALUES LESS THAN (801000) (
SUBPARTITION s14,
SUBPARTITION s15
),
PARTITION p8 VALUES LESS THAN (901000) (
SUBPARTITION s16,
SUBPARTITION s17
),
PARTITION p9 VALUES LESS THAN MAXVALUE(
SUBPARTITION s18,
SUBPARTITION s19
)
);
//查询语句,增加分区前查询耗时 0.976s,增加分区后查询耗时 0.113s,可看到有 0.863s的增速
select * from `user_login_log` where user_id>=50001 and user_id<=100000;
2.3 分区的其他操作
//删除分区
ALTER TABLE `user_login_log` REMOVE PARTITIONING;
//删除分区的某部分
ALTER table `user_login_log` DROP PARTITION p1;