實戰mysql分區
前些天拿到一個表,將近有4000w數據,沒有任何索引,主鍵。(建這表的絕對是個人才)
這是一個日誌表,記錄了遊戲中物品的產出與消耗,原先有一個後臺對這個表進行統計。。。。。(這要用超級計算機才能統計得出來吧),只能幫前人填坑了。。。。
數據太大,決定用分區來重構。
如果你發現是empty,說明你的mysql版本不夠,分區至少要5.1
下面針對業務查詢,決定用時間來做range分區(還有list,hash等類型),一個月一個區.
按照RANGE分區的表是通過如下一種方式進行分區的,每個分區包含那些分區表達式的值位於一個給定的連續區間內的行。這些區間要連續且不能相互重疊,使用VALUES LESS THAN操作符來進行定義。
新建一個表:
Sql代碼
- CREATE TABLE `xxxxxxxx` (
- `crttm` int(11) NOT NULL,
- `srvid` int(11) NOT NULL,
- `evtid` int(11) NOT NULL,
- `aid` int(11) NOT NULL,
- `rid` int(11) NOT NULL,
- `itmid` int(11) NOT NULL,
- `itmnum` int(11) NOT NULL,
- `gdtype` int(11) NOT NULL,
- `gdnum` int(11) NOT NULL,
- `islmt` int(11) NOT NULL,
- KEY `crttm` (`crttm`),
- KEY `itemid` (`itmid`),
- KEY `srvid` (`srvid`),
- KEY `gdtype` (`gdtype`)
- ) ENGINE=myisam DEFAULT CHARSET=utf8
- PARTITION BY RANGE (crttm)
- (
- PARTITION p201303 VALUES LESS THAN (unix_timestamp(‘2013-04-01‘)),
- PARTITION p201304 VALUES LESS THAN (unix_timestamp(‘2013-05-01‘)),
- PARTITION p201305 VALUES LESS THAN (unix_timestamp(‘2013-06-01‘)),
- PARTITION p201306 VALUES LESS THAN (unix_timestamp(‘2013-07-01‘)),
- PARTITION p201307 VALUES LESS THAN (unix_timestamp(‘2013-08-01‘)),
- PARTITION p201308 VALUES LESS THAN (unix_timestamp(‘2013-09-01‘)),
- PARTITION p201309 VALUES LESS THAN (unix_timestamp(‘2013-10-01‘)),
- PARTITION p201310 VALUES LESS THAN (unix_timestamp(‘2013-11-01‘)),
- PARTITION p201311 VALUES LESS THAN (unix_timestamp(‘2013-12-01‘)),
- PARTITION p201312 VALUES LESS THAN (unix_timestamp(‘2014-01-01‘)),
- PARTITION p201401 VALUES LESS THAN (unix_timestamp(‘2014-02-01‘))
- );
註意:
1. primary key和unique key必須包含在分區key的一部分,否則在創建primary key和unique index時會報”ERROR 1503 (HY000)“
mysql> create unique index idx_employees1_job_code on employees1(job_code); ERROR 1503 (HY000): A UNIQUE INDEX must include all columns in the table‘s partitioning function 或 mysql> ALTER TABLE `skate`.`employees1` ADD PRIMARY KEY (`id`) ; ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table‘s partitioning function
2. 範圍分區添加分區只能在最大值後面追加分區 3. 所有分區的engine必須一樣 4. 範圍分區分區字段:integer、數值表達式、日期列,日期函數表達式(如year(),to_days(),to_seconds(),unix_timestamp())
將舊的表數據導入到新表後,看到新表的數據都分布到不同的區了!
維護命令:
添加分區
Sql代碼- alter table xxxxxxx add partition (partition p0 values less than(1991)); //只能添加大於分區鍵的分區
刪除分區
Sql代碼- alter table xxxxxxx drop partition p0; //可以刪除任意分區
刪除分區數據
Sql代碼- alter table xxxxxx truncate partition p1,p2;
- alter table xxxxxx truncate partition all;
- 或
- delete from xxxxxx where separated < ‘2006-01-01‘ or (separated >= ‘2006-01-01‘ and separated<‘2011-01-01‘);
重定義分區(包括重命名分區,伴隨移動數據;合並分區)
Sql代碼- alter table xxxxx reorganize partition p1,p3,p4 into (partition pm1 values less than(2006),
- partition pm2 values less than(2011));
rebuild重建分區
Sql代碼- alter table xxxxxx rebuild partition pm1/all; //相當於drop所有記錄,然後再reinsert;可以解決磁盤碎片
優化表
Sql代碼- alter table tt2 optimize partition pm1; //在大量delete表數據後,可以回收空間和碎片整理。但在5.5.30後支持。在5.5.30之前可以通過recreate+analyze來替代,如果用rebuild+analyze速度慢
analzye表
Sql代碼- alter table xxxxxx analyze partition pm1/all;
check表
Sql代碼- alter table xxxxxx check partition pm1/all;
Sql代碼
- show create table employees2; //查看分區表的定義
- show table status like ‘employees2‘\G; //查看表時候是分區表 如“Create_options: partitioned”
- select * from information_schema.KEY_COLUMN_USAGE where table_name=‘employees2‘; //查看索引
- SELECT * FROM information_schema.partitions WHERE table_name=‘employees2‘ //查看分區表
- explain partitions select * from employees2 where separated < ‘1990-01-01‘ or separated > ‘2016-01-01‘; //查看分區是否被select使用
實戰mysql分區