1. 程式人生 > >SQL表分割槽 partition的用法

SQL表分割槽 partition的用法

1.分表與表分割槽的區別
1.1 關於分表
分表是將一個大表分為幾個或是多個小表,例如:table_1每天有1Kw的資料量,table_1隨便時間的增長會越來越大,最終達到mysql表的極限,在這種比較極端的情況下
我們可以考慮對table_01進行分表操作,即每天生成與table_1表同樣的表,每天一張即table_1_20120920
更多詳細:http://blog.51yip.com/mysql/949.html

1.2 關於分割槽

以myisam為例子,mysql資料庫中的資料是以檔案的形勢存在磁碟上,一張表主要對應著三個檔案,一個是frm存放表結構檔案,一個存放表資料的,一個是myi存表索引。
也就是將一個表文件分為多個表文件在磁碟上進行存取,提高對io的使用。

1.3 是否支援分割槽

mysql> show variables like ‘%partition%’;
+——————-+——-+
| Variable_name | Value |
+——————-+——-+
| have_partitioning | YES |
+——————-+——-+
出現YES表示當前版本支援表分割槽

1.4 檢視分割槽表資訊
select * from INFORMATION_SCHEMA.PARTITIONS where TABLE_SCHEMA=’tablename’
2.如何分割槽
2.1 分割槽方法
分割槽有二個方法: 水平分割槽、垂直分割槽
2.2 分割槽的型別
=== 水平分割槽的幾種模式:===
* Range(範圍) – 這種模式允許DBA將資料劃分不同範圍。例如DBA可以將一個表通過年份劃分成三個分割槽,80年代(1980′s)的資料,90年代(1990′s)的資料以及任何在2000年(包括2000年)後的資料。

* Hash(雜湊) – 這中模式允許DBA通過對錶的一個或多個列的Hash Key進行計算,最後通過這個Hash碼不同數值對應的資料區域進行分割槽,。例如DBA可以建立一個對錶主鍵進行分割槽的表。

* Key(鍵值) – 上面Hash模式的一種延伸,這裡的Hash Key是MySQL系統產生的。

* List(預定義列表) – 這種模式允許系統通過DBA定義的列表的值所對應的行資料進行分割。例如:DBA建立了一個橫跨三個分割槽的表,分別根據2004年2005年和2006年值所對應的資料。

* Composite(複合模式) – 很神祕吧,哈哈,其實是以上模式的組合使用而已,就不解釋了。舉例:在初始化已經進行了Range範圍分割槽的表上,我們可以對其中一個分割槽再進行hash雜湊分割槽。

= 垂直分割槽(按列分)=
舉個簡單例子:一個包含了大text和BLOB列的表,這些text和BLOB列又不經常被訪問,這時候就要把這些不經常使用的text和BLOB了劃分到另一個分割槽,在保證它們資料相關性的同時還能提高訪問速度。
2.2 程式碼演示
range分割槽如下:

–按天進行劃分
錯誤程式碼
create table part_range
(
id bigint not null auto_increment,
ftime date,
str text
)engine=myisam
partition by range (ftime)
(
partition p0 values less than (to_days(’2012-09-21′)),
partition p1 values less than (to_days(’2012-09-22′))
)
錯誤原因:
1. 在partition by range (ftime),ftime需要加to_days轉成數字
2.進行分割槽的欄位需要是主鍵的一部分1
使用以上語句建立時報錯
‘A PRIMARY KEY must include all columns in the table’s partitioning function”
預設分割槽限制分割槽欄位必須是主鍵(PRIMARY KEY)的一部分

–按天進行分割槽
–直接使用時間列不可以,RANGE分割槽函式返回的列需要是整型。
create table part_range
(
id bigint not null auto_increment,
ftime date,
str text,
primary key(id,ftime)
)engine=myisam
partition by range (to_days(ftime))
(
partition p0 values less than (to_days(’2012-09-21′)),
partition p1 values less than (to_days(’2012-09-22′)),
PARTITION p3 VALUES LESS THAN MAXVALUE
);

–按小時進行分割槽
create table part_range_day
(
id bigint not null auto_increment,
ftime datetime,
str text,
primary key(id,ftime)
)engine=myisam
partition by range(hour(ftime))
(
partition p0 values less than (1),
partition p1 values less than(2),
PARTITION p3 VALUES LESS THAN MAXVALUE
)
[Err] 1493 – VALUES LESS THAN value must be strictly increasing for each partition

使用id進行劃分時

–按id進行劃分,id只能是由小到大
create table part_range_id
(
id bigint not null auto_increment,
ftime datetime,
str text,
primary key(id,ftime)
)engine=myisam
partition by range (id)
(
partition p0 values less than (10000),
partition p1 values less than (20000),
partition p2 values less than maxvalue
)

–使用list

create table part_range_list
(
id bigint not null auto_increment,
ftime datetime,
str text,
primary key(id,ftime)
)engine=myisam
partition by list (id)
(
partition p0 values in (0,1),
partition p1 values in (2,4)
)

–5.5之後的mysql說可以支援字元目前使用的5.5.24版本,使用字元時依然提示 [Err] 1697 – VALUES value for partition ‘p0′ must have type INT

3.效能測試

硬體:3.6G 記憶體 cpu Intel(R) Pentiun(R)
軟體:win xp2 32位
–沒有加分割槽表part_no_test,myisam引擎

create table part_no_test
(
id bigint primary key auto_increment,
ftime datetime,
str text
)engine=myisam

–加入分割槽的表part_test,myisam引擎,以小時劃分四個區
create table part_test
(
id bigint auto_increment,
ftime datetime,
str text,
primary key(id,ftime)
)engine=myisam
partition by range(hour(ftime))
(
partition p0 values less than (6),
partition p1 values less than (12),
partition p3 values less than (18),
partition p4 values less than maxvalue
)

–隨機資料構造,構造2kw資料量
INSERT INTO part_test(ftime,str)values(FROM_UNIXTIME(unix_timestamp(’2012-09-20 08:00:00′)+FLOOR(7 + (RAND() * 360000))),’sss’);
生成資料儲存過程
—生成part_no_test資料
drop procedure if exists part_no_insert_data;
create procedure part_insert_data()
begin
set @id=20000000;
while @id>0 do
INSERT INTO part_no_test(ftime,str)values(FROM_UNIXTIME(unix_timestamp(’2012-09-20 08:00:00′)+FLOOR(7 + (RAND() * 360000))),RAND()*RAND()*100000000000);
set @[email protected];
end while;
end;

—生成part_test資料

drop procedure if exists part_insert_data;
create procedure part_insert_data()
begin
set @id=20000000;
while @id>0 do
INSERT INTO part_test(ftime,str)values(FROM_UNIXTIME(unix_timestamp(’2012-09-20 08:00:00′)+FLOOR(7 + (RAND() * 360000))),RAND()*RAND()*100000000000);
set @[email protected];
end while;
end;

–有分割槽查詢語句
select * from part_test a where a.ftime>’2012-09-20 10:00:00′ and a.ftime<’2012-09-20 12:00:00′;

執行時間:09.906s

–無分割槽查詢語句
select * from part_no_test a where a.ftime>’2012-09-20 10:00:00′ and a.ftime<’2012-09-20 12:00:00′;

執行時間:23.281s

附:
Mysql可用的分割槽函式
DAY()
DAYOFMONTH()
DAYOFWEEK()
DAYOFYEAR()
DATEDIFF()
EXTRACT()
HOUR()
MICROSECOND()
MINUTE()
MOD()
MONTH()
QUARTER()
SECOND()
TIME_TO_SEC()
TO_DAYS()
WEEKDAY()
YEAR()
YEARWEEK() 等
當然,還有FLOOR(),CEILING() 等,前提是使用這兩個分割槽函式的分割槽健必須是整型。
要小心使用其中的一些函式,避免犯邏輯性的錯誤,引起全表掃描。

注:
1.分割槽的新增、刪除每次只能是一個
2.maxvalues 後面不能再加分割槽
3.分割槽鍵必須包含在主鍵中 ERROR 1503 (HY000): A PRIMARY KEY must include all columns in the table’s partitioning function’
4.ERROR 1503 (HY000): A UNIQUE INDEX must include all columns in the table’s partitioning function’說明在表上建約束索引(如唯一索引,普通索引可以)會有問題,必須把約束索引列包含在分割槽健內
5.只有RANGE和LIST分割槽才能有子分割槽,每個分割槽的子分割槽數量必須相同,
6. MYSQL將NULL值視為0.自動插入最小的分割槽中。

= 初步結論 =
* 分割槽和未分割槽佔用檔案空間大致相同 (資料和索引檔案)
* 如果查詢語句中有未建立索引欄位,分割槽時間遠遠優於未分割槽時間
* 如果查詢語句中欄位建立了索引,分割槽和未分割槽的差別縮小,分割槽略優於未分割槽。
= 最終結論 =
* 對於大資料量,建議使用分割槽功能。
* 去除不必要的欄位
* 根據手冊, 增加myisam_max_sort_file_size 會增加分割槽效能