首页 > 代码库 > MySQL3-分区与分表

MySQL3-分区与分表

目录
零、主要参考网页
一、概述
二、分区类型以及创建方式
三、分区表的管理
四、获取分区表信息
五、分区的局限与分表
 
 
 
零、主要参考网页
http://www.2cto.com/database/201503/380348.html【mysql分表和表分区详解】
http://www.cnblogs.com/zemliu/archive/2013/07/21/3203511.html【MySQL分区表】
http://x125858805.iteye.com/blog/2068120【MYSQL--表分区、查看分区(转)】
http://blog.csdn.net/tjcyjd/article/details/11194489【深入解析MySQL分区(Partition)功能】
 
 
 
一、概述
1、功能:主要目的是为了在特定的SQL操作中减少数据读写的总量以缩减sql语句的响应时间,同时对于应用来说分区完全是透明的。
2、水平分区和垂直分区:水平分区是对行进行分区;垂直分区是对列进行分区,减小每个分区中数据的宽度,使用很少。
3、分区类型:RANGE分区、LIST分区、HASH分区、KEY分区以及复合分区。
4、MySQL分区实现:逻辑上是一个独立的表,但是底层由多个物理子表实现。
5、一个表最多只能有1024个分区。
6、查询时只能根据列过滤分区,使用列的表达式不行;即便这个表达式就是分区函数也不行。
 
 
 
二、分区类型以及创建方式
0、共性
(1)如果表含有主键,则做分区的列必须包含在主键中;如果表不含有主键,则无所谓。
(2)分区键必须是INT类型,或者通过表达式返回INT类型,可以为NULL。唯一的例外是当分区类型为KEY分区的时候,可以使用其他类型的列作为分区键( BLOB or TEXT 列除外)。【注意,to_days函数可以将一个日期转化为INTEGER,作为分区表达式,而且有函数将字符串转化为日期;但是如果将字符串转为日期,在使用to_days,则不能作为分区表达式;这个时候要考虑换列做分区,或者使用key分区】
(3)如果分区键所在列没有not null约束:range分区表的null行将被保存在范围最小的分区;list分区表的null行将被保存到list为0的分区;在按HASH和KEY分区的情况下,任何产生NULL值的表达式mysql都视同它的返回值为0。为了避免这种情况的产生,建议分区键设置成NOT NULL。
(4)对分区表的分区键创建索引,那么这个索引也将被分区,分区表没有全局索引一说。注意,oracle是在分区与索引时,是可以选择全局索引还是分区索引的。
 
1、RANGE 分区:基于属于一个给定连续区间的列值,把多行分配给分区。
(1)示例1:
create table emp(
    empno varchar(20) not null,
    empname varchar(20),
    deptno int,
    birthdate date,
    salary int
) partition by range(salary)(
    partition p1 values less than (1000),
    partition p2 values less than (2000),
    partition p3 values less than maxvalue
);
(2)示例2:(在本例中,没有直接使用列而是使用了表达式year(birthdate);使用表达式必须有返回值)
create table emp(
    empno varchar(20) not null ,
    empname varchar(20),
    deptno int,
    birthdate date not null,
    salary int
) partition by range(year(birthdate))(
    partition p1 values less than (1980),
    partition p2 values less than (1990),
    partition p3 values less than maxvalue
);
(3)maxvalue只能出现在最后一个分区;如果没有使用形如maxvalue,可能导致插入的数据不属于任何分区,从而导致数据无法插入(如:Table has no partition for value ……)
 
2、LIST 分区:类似于按RANGE分区,区别在于LIST分区是基于列值匹配一个离散值集合中的某个值来进行选择;如果插入的数据不能匹配任何分区,则插入失败。
create table emp(
    empno varchar(20) not null ,
    empname varchar(20),
    deptno int,
    birthdate date not null,
    salary int
) partition by list(deptno)(
    partition p1 values in (10),
    partition p2 values in (20),
    partition p3 values in (30)
);
 
3、HASH分区:基于用户定义的表达式的返回值进行选择,该表达式使用一个或多个列值进行计算;这个表达式可以是任何产生非负整数值的表达式。
(1)目标:确保数据在预先确定数目的分区中平均分布。不需要指定一行数据在哪个分区中(RANGE和LIST需要),MySQL自动完成;只需要指定表达式以及分区数量。hash分区和key分区,经过测试,有个奇怪的特点:当分区数量为奇数时,分布较为平均;当分区质量为偶数时,则会出现一半分区没有元素的现象。【网上说是质数和合数,但我测试发现,2不平均,而9/15等则较为平均,故猜测是奇数和偶数】
(2)示例
create table emp(
    empno varchar(20) not null ,
    empname varchar(20),
    deptno int,
    birthdate date not null,
    salary int
) partition by hash(year(birthdate))
    partitions 4;//4表示分成4份
 
 
4、KEY分区:类似于按HASH分区,区别在于KEY分区不能指定表达式,只能指定一列或多列;同样需要指定分区数量。
create table emp(
    empno varchar(20) not null ,
    empname varchar(20),
    deptno int,
    birthdate date not null,
    salary int
) partition by key(birthdate)
    partitions 4;
 
5、复合分区:包括range-hash、range-key、list-hash、list-key
示例:range-hash
create table emp(
empno varchar(20) not null ,
empname varchar(20),
deptno int,
birthdate date not null,
salary int
) partition by range(salary)
subpartition by hash(year(birthdate))
subpartitions 3(
partition p1 values less than (2000),
partition p2 values less than maxvalue
);
 
 
 
三、分区表的管理
1、删除分区:同时删除分区内的数据;只可以用于range和list。
alter table emp drop partition p1;
alter table emp drop partition p2,p3;
 
2、增加分区:如果range分区中使用了maxvalue,则无法在后面增加分区,因为形如maxvalue必须是最后一个分区;可以先删除再添加,但是如果有数据在最后一个分区,会导致数据丢失。只可以用于range和list;不会丢失数据。
alter table emp add partition (partition p3 values less than (4000));
alter table emp add partition (partition p3 values in (40));
 
3、分解分区:只可以用于range和list;不会丢失数据。
alter table emp reorganize partition p1 into(
partition p1 values less than (100),
partition p3 values less than (1000)
);
 
4、合并分区:只可以用于range和list;不会丢失数据。
alter table emp reorganize partition p1,p3 into (partition p1 values less than (1000));
 
5、重新定义分区表:可以用于四种分区表;不会丢失数据。
alter table emp partition by hash(salary)partitions 7;---hash
alter table emp partition by range(salary)(
partition p1 values less than (2000),
partition p2 values less than (4000)
);---range
 
6、删除所有分区:可以用于四种分区表;不会丢失数据。
alter table emp remove partitioning;
 
7、重建分区:可以用于四种分区表;不会丢失数据。当用于hash和key分区时,可以先查询分区名称再重建(因为不是我们指定的),不过一般是p0,p1,p2...的形式。用于整理分区碎片,效果与先删除保存在分区中的记录,再将它们插入相同。
ALTER TABLE emp rebuild partition p1,p2;
 
8、优化分区:可以用于四种分区表;不会丢失数据。如果从分区中删除了大量的行,或者对一个带有可变长度的行作了许多修改,可以用来收回没有使用的空间,并整理分区数据文件的碎片。【我的MySQL不支持:Table does not support optimize on partitions. All partitions will be rebuilt and analyzed.】
ALTER TABLE emp optimize partition p1,p2;
 
9、保存分区:可以用于四种分区表;不会丢失数据。读取并保存分区的键分布;保存到哪里呢???
ALTER TABLE emp3 analyze partition p1,p2;
 
10、检查分区:可以用于四种分区表;不会丢失数据。判断数据或索引是否已经被破坏,如果破坏使用修复分区进行修复。
ALTER TABLE emp CHECK partition p1,p2;
 
11、修复分区:可以用于四种分区表;不会丢失数据。
ALTER TABLE emp repair partition p1,p2;
 
 
 
四、获取分区表信息
1、show create table 表名
2、show table status:可以查看是不是分区表;不加表明,显示数据库内所有表的状态
3、查看information_schema.partitions表 
select
partition_name part,
partition_expression expr,
partition_description descr,
table_rows
from information_schema.partitions where
table_schema = schema()
and table_name=‘表名‘;
应该注意到,查询到分区表的数据统计未必准确(有时连续查询没有变动的表结果都可能不同);准确与否与搜索引擎有关,比如Innodb的不准确。
4、explain partitions select语句:通过此语句来显示扫描哪些分区,及他们是如何使用的;因此可以查看分区是否对查询过程有优化效果。
 
 
 
五、分区的局限与分表
1、分区与索引
(1)作用类似
在执行查询时,优化器会根据分区定义过滤那些没有我们需要数据的分区,否则分区对查询的优化就没有什么效果了。因此,查询条件应该与分区列匹配。
理解分区:可以将分区当做索引的最初形态,以代价非常小的方式定位到需要的数据在哪一片“区域”。这样也就可以理解,无论是分区还是索引,都要求查询条件与之匹配,查询才有优化效果。
(2)有索引为什么还需要分区
当表数据量超大的时候,索引是有问题的。一方面,除非索引覆盖了查询,否则数据库根据索引扫描的结果去数据库中查找,如果数据量巨大,将产生大量随机I/O,数据库响应时间会超长。另一方面,索引也会很大。
(3)实现细节
分区表的底层由多个物理子表实现,因此分区表的索引只是在各个底层表上各自加上一个完全相同的索引;没有全局索引一说。
(4)问题:分区列和索引列不匹配
如果分区列和索引列不匹配,那么根据索引的条件查询,不能够过滤分区;就会导致需要把每个分区的索引都读到内存,效率极低,尽量避免。
但是实际上,有些时候很难避免索引列与分区列不一致:比如某些表有不止一个索引。
此时,可以考虑分表。
 
2、分表
(1)顾名思义,当数据量过大时,将不同的数据放到不同的表中。选取用于分表的字段和规则应该注意,这个字段应比较常用(因为每次增删改查都需要根据这个字段确定使用哪个表),也尽量不要使用完全随机数(不好根据规则确定表)。
(2)动态sql:在应用层进行判断,选择增删改查所使用的表;代码略繁琐,且随着新加表,需要发版。使用Hibernate的sql功能,直接用sql语句和表名进行操作;PO不与表绑定(严格来说不是PO)。
(3)NamingStrategy:传入一个表名,命名策略可以输出一个表名;但是由于输入只有表名,因此不可能根据数据的不同动态选择表名。命名策略一般做的事情是进行一些大小写转换,加前后缀,或者在表名中加入当前时间的信息(这个在每天的表都需要单独存,且以后不需要访问今天的表或访问时会带上时间时比较有用)。
(4)hibernate shards:google提交给hibernate社区的源码。每个分片都要有自己的配置文件,强项是分库。
(5)Inceptor:在hibernate生成最终的sql语句之前,对sql进行一些改变。这个功能挺强大,而且将对分表的处理放在了最底层,逻辑上比较通顺。但是也有一些弊端:代码繁琐;每个sql都会被拦截,可能会出问题;对写sql的格式会有一定要求(这样拦截时才容易判断出哪些是真正需要拦截的);不直观。
 
 

MySQL3-分区与分表