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 MAXVALUE
);
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)
);
如果试图插入列值(或分区表达式的返回值)不在分区值列表中的一行时,那么“INSERT”查询将失败并报错
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(YEAR(hired))
PARTITIONS 4;
MySQL还支持线性哈希功能,它与常规哈希的区别在于,线性哈希功能使用的一个线性的2的幂(powers-of-two)运算法则,而常规 哈希使用的是求哈希函数值的模数。
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 LINEAR HASH(YEAR(hired))
PARTITIONS 4;
KEY 分区:按照KEY进行分区类似于按照HASH分区,除了HASH分区使用的用户定义的表达式,而KEY分区的 哈希函数是由MySQL 服务器提供。MySQL 簇(Cluster)使用函数MD5()来实现KEY分区;
col1 INT NOT NULL,
col2 CHAR(5),
col3 DATE
)
PARTITION BY LINEAR KEY (col1)
PARTITIONS 3;
CREATE TABLE ts (id INT, purchased DATE)
PARTITION BY RANGE(YEAR(purchased))
SUBPARTITION BY HASH(TO_DAYS(purchased))
(
PARTITION p0 VALUES LESS THAN (1990)
(
SUBPARTITION s0,
SUBPARTITION s1
),
PARTITION p1 VALUES LESS THAN (2000)
(
SUBPARTITION s2,
SUBPARTITION s3
),
PARTITION p2 VALUES LESS THAN MAXVALUE
(
SUBPARTITION s4,
SUBPARTITION s5
)
);
子分区可以用于特别大的表,在多个磁盘间分配数据和索引。假设有6个磁盘,分别为/disk0, /disk1, /disk2等。现在考虑下面的例子:
PARTITION BY RANGE(YEAR(purchased))
SUBPARTITION BY HASH(TO_DAYS(purchased))
(
PARTITION p0 VALUES LESS THAN (1990)
(
SUBPARTITION s0
DATA DIRECTORY = '/disk0/data'
INDEX DIRECTORY = '/disk0/idx',
SUBPARTITION s1
DATA DIRECTORY = '/disk1/data'
INDEX DIRECTORY = '/disk1/idx'
),
PARTITION p1 VALUES LESS THAN (2000)
(
SUBPARTITION s0
DATA DIRECTORY = '/disk2/data'
INDEX DIRECTORY = '/disk2/idx',
SUBPARTITION s1
DATA DIRECTORY = '/disk3/data'
INDEX DIRECTORY = '/disk3/idx'
),
PARTITION p2 VALUES LESS THAN MAXVALUE
(
SUBPARTITION s0
DATA DIRECTORY = '/disk4/data'
INDEX DIRECTORY = '/disk4/idx',
SUBPARTITION s1
DATA DIRECTORY = '/disk5/data'
INDEX DIRECTORY = '/disk5/idx'
)
);
从一个按照RANGE或LIST分区的表中删除一个分区,可以使用带一个DROP PARTITION子句的ALTER TABLE命令来实现
ALTER TABLE tr DROP PARTITION p2;
由“ALTER TABLE ... DROP PARTITION”语句引起的、从表中删除的行数并没有被服务器报告出来
如果希望改变表的分区而又不丢失数据,使用“ALTER TABLE ... REORGANIZE PARTITION”语句
PARTITION p0 VALUES LESS THAN (1970)
);
使用“REORGANIZE PARTITION”拆分或合并分区,没有数据丢失。在执行上面的语句中,MySQL 把保存在分区s0和s1中的所有数据都移到分区p0中。
不能使用与从按照RANGE或LIST分区的表中删除分区相同的方式来从HASH或KEY分区的表中删除分区。但是,可以使用“ALTER TABLE ... COALESCE PARTITION”命令来合并HASH或KEY分区。
MySQL5.1提供的分区技术,令人对其充满希望。
根据官方文档,分区技术能够极大的帮助DBA人员。支持的分区模式包括:
Range
List
Hash
Key
----
安装配置记录:
tar -xzvf mysql-5.1.16-beta-linux-i686-icc-glibc23.tar.gz
mv mysql-5.1.16-beta-linux-i686-icc-glibc23 /usr/local/mysql-5.1
修改启动脚本,启动
检查当前版本是否支持分区:
SHOW VARIABLES LIKE '%partition%';
测试带分区的表:(From 手册)
CREATE TABLE tr (id INT, name VARCHAR(50), purchased DATE)
PARTITION BY RANGE(YEAR(purchased))
(
PARTITION p0 VALUES LESS THAN (1990),
PARTITION p1 VALUES LESS THAN (1995),
PARTITION p2 VALUES LESS THAN (2000),
PARTITION p3 VALUES LESS THAN (2005)
);
INSERT INTO tr VALUES
(1, 'desk organiser', '2003-10-15'),
(2, 'CD player', '1993-11-05'),
(3, 'TV set', '1996-03-10'),
(4, 'bookcase', '1982-01-10'),
(5, 'exercise bike', '2004-05-09'),
(6, 'sofa', '1987-06-05'),
(7, 'popcorn maker', '2001-11-22'),
(8, 'aquarium', '1992-08-04'),
(9, 'study desk', '1984-09-16'),
(10, 'lava lamp', '1998-12-25');
从服务器上可以看到文件结构为:
10.10.82.83 [testuser]$ l
total 404M
-rw-rw---- 1 mysql mysql 8.5K 2007-03-14 15:26:29 tr.frm
-rw-rw---- 1 mysql mysql 32 2007-03-14 15:26:29 tr.par
-rw-rw---- 1 mysql mysql 68 2007-03-14 15:26:48 tr#P#p0.MYD
-rw-rw---- 1 mysql mysql 1.0K 2007-03-14 15:26:48 tr#P#p0.MYI
-rw-rw---- 1 mysql mysql 48 2007-03-14 15:26:48 tr#P#p1.MYD
-rw-rw---- 1 mysql mysql 1.0K 2007-03-14 15:26:48 tr#P#p1.MYI
-rw-rw---- 1 mysql mysql 44 2007-03-14 15:26:48 tr#P#p2.MYD
-rw-rw---- 1 mysql mysql 1.0K 2007-03-14 15:26:48 tr#P#p2.MYI
-rw-rw---- 1 mysql mysql 84 2007-03-14 15:26:48 tr#P#p3.MYD
-rw-rw---- 1 mysql mysql 1.0K 2007-03-14 15:26:48 tr#P#p3.MYI
说明创建分区成功。
测试分区管理,删除:
ALTER TABLE tr DROP PARTITION p2;
添加:
ALTER TABLE tr ADD PARTITION (PARTITION p2 VALUES LESS THAN (2000));注意:
1,删除分区后,分区内的数据也不可恢复的删除了。
2,只有range和list分区可以进行无数据影响的添加操作。其他种类的分区,不要进行分区管理。或者是,先把数据全导出,改变分区结构后再导入。
3,作为分区依据的列值是可以修改的,修改后会转移到对应分区中。(这点很有意义哟~)
下面是实战:
CREATE TABLE `user` (
`id` int(11) not null auto_increment,
`cn` varchar(22) not null default '',
`nickname` varchar(32) not null default '',
`genderid` tinyint(1) unsigned default null,
`artnum` int(8) unsigned default '0',
`elitenum` int(8) unsigned default '0',
`commnum` int(11) not null default '0',
`delnum` int(8) unsigned default '0',
`loginnum` int(8) unsigned default '1',
`linetime` int(8) unsigned default '0',
`lastdate` datetime default null,
`power` int(10) not null default '0',
`score` int(8) default '0',
`inputdate` datetime default null,
`finallydate` datetime default null,
`ad3` tinyint(4) not null default '0',
primary key (`id`),
key `nickname` (`nickname`),
key `finallydate` (`finallydate`)
) ENGINE=MyISAM DEFAULT CHARSET=gb2312 AUTO_INCREMENT=4589157
PARTITION BY RANGE(id)
(
PARTITION p5 VALUES LESS THAN (5000000),
PARTITION p6 VALUES LESS THAN (6000000),
PARTITION p7 VALUES LESS THAN (7000000),
PARTITION p8 VALUES LESS THAN (8000000),
PARTITION p9 VALUES LESS THAN (9000000),
PARTITION p10 VALUES LESS THAN (10000000),
PARTITION p11 VALUES LESS THAN (11000000),
PARTITION p12 VALUES LESS THAN (12000000),
PARTITION p13 VALUES LESS THAN (13000000),
PARTITION p14 VALUES LESS THAN (14000000),
PARTITION p15 VALUES LESS THAN (15000000),
PARTITION p16 VALUES LESS THAN (16000000),
PARTITION p0 VALUES LESS THAN MAXVALUE
);
关入400万数据,性能对比:
(待补充)
方案二,使用Key进行划分
create table `user2` (
`cn` varchar(22) not null default '',
`nickname` varchar(32) not null default '',
`genderid` tinyint(1) unsigned default null,
`artnum` int(8) unsigned default '0',
`elitenum` int(8) unsigned default '0',
`commnum` int(11) not null default '0',
`delnum` int(8) unsigned default '0',
`loginnum` int(8) unsigned default '1',
`linetime` int(8) unsigned default '0',
`lastdate` datetime default null,
`power` int(10) not null default '0',
`score` int(8) default '0',
`inputdate` datetime default null,
`finallydate` datetime default null,
`ad3` tinyint(4) not null default '0',
primary key (`cn`),
key `nickname` (`nickname`),
key `finallydate` (`finallydate`)
) engine=myisam default charset=gb2312
partition by key(cn)
partitions 3;
增加分区数:ALTER TABLE user2 ADD PARTITION PARTITIONS 10;
减少分区数:ALTER TABLE user2 COALESCE PARTITION 6;
增加和减少分区时,数据并不丢失。
一个不很方便的地方在于,当划分分区时,有unique的列时可能会拒绝操作。
另外,关于性能方面。range,list划分会对提高性能有帮助,但是作用多大,还是跟具体应用有关的。可以肯定的是,不会比我们传统上用程序逻辑将数据分散到多个表的方法效率更高,只是更方便而已。对于hash,key的划分,需要消耗大量计算时间,如果设计不当,可能还会造成性能的下降。所以,这也是我没有立即写性能对比数据的原因。
以后在实际应用中,采用分区技术确实能够有效提高性能得到验证后,再回来补充性能部分的内容。
~~呵呵~~
=================================================================
mysql按时间字段进行分区 ,后跨分区查询
MYSQL版本:MySQL5.1.7-noinstall-beta(win32)
--建表语句
DROP TABLE IF EXISTS MD_TEST;
CREATE TABLE MD_TEST
(
STAT_TIME DATETIME NOT NULL,
VALUE INT UNSIGNED NOT NULL
)
PARTITION BY RANGE (DAYOFYEAR(STAT_TIME)) (
PARTITION p1 VALUES LESS THAN (1),
PARTITION p2 VALUES LESS THAN (2),
PARTITION p3 VALUES LESS THAN MAXVALUE);
--插入测试数据库
INSERT INTO `md_test` (`STAT_TIME`, `VALUE`) VALUES
('2007-01-01',100),
('2007-01-02',200),
('2007-01-21',120);
--跨分区查询
SELECT STAT_TIME,SUM(VALUE) FROM md_test
WHERE STAT_TIME>=DATE'2007-01-01' AND STAT_TIME<=DATE'2007-01-03'
GROUP BY STAT_TIME