一、概述
當 MySQL的總記錄數超過了100萬後,會出現性能的大幅度下降嗎?答案是肯定的,但是,性能下降>的比率不一而同,要看系統的架構、應用程序、還有>包括索引、服務器硬件等多種因素而定。當有網友問我這個問題的時候,我最常見的回答>就是:分表,可以根據id區間或者時間先後順序等多種規則來分表。分表很容易,然而由此所帶來的應用程序甚至是架構方面的改動工作卻不>容小觑,還包括將來的擴展性等。
在以前,一種解決方案就是使用 MERGE
類型,這是一個非常方便的做飯。架構和程序基本上不用做改動,不過,它的缺點是顯見的:
1.只能在相同結構的 MyISAM 表上使用
2.無法享受到 MyISAM 的全部功能,例如無法在 MERGE 類型上執行 FULLTEXT 搜索
3.它需要使用更多的文件描述符
4.讀取索引更慢
這個時候,MySQL 5.1 中新增的分區(Partition)功能的優勢也就很明顯了:
1.與單個磁盤或文件系統分區相比,可以存儲更多的數據
2.很容易就能刪除不用或者過時的數據
3.一些查詢可以得到極大的優化
4.涉及到 SUM()/COUNT() 等聚合函數時,可以並行進行
5.IO吞吐量更大
分區允許可以設置為任意大小的規則,跨文件系統分配單個表的多個部分。實際上,表的不同部分在不同的位置被存儲為單獨的表。
分區應該注意的事項:
1、 做分區時,要麼不定義主鍵,要麼把分區字段加入到主鍵中。
2、 分區字段不能為NULL,要不然怎麼確定分區范圍呢,所以盡量NOT NULL
二、分區的類型
1.RANGE 分區:基於屬於一個給定連續區間的列值,把多行分配給分區。
2.LIST 分區:類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。
2.HASH分區:基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算。這個函數可以包>含MySQL中有效的、產生非負整數值的任何表達式。
3.KEY分區:類似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL服務器提供其自身的哈希函數。必須有一列或多列包含>整數值。
可以通過使用SHOW VARIABLES命令來確定MySQL是否支持分區,例如:
復制代碼 代碼如下:
mysql> SHOW VARIABLES LIKE '%partition%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| have_partition_engine | YES |
+-----------------------+-------+
1 row in set (0.00 sec)
復制代碼 代碼如下:
mysql> SHOW VARIABLES LIKE '%partition%';
+-----------------------+-------+
| Variable_name | Value |
+-----------------------+-------+
| have_partition_engine | YES |
+-----------------------+-------+
1 row in set (0.00 sec)
1、range分區
復制代碼 代碼如下:
create table t_range(
id int(11),
money int(11) unsigned not null,
date datetime
)partition by range(year(date))(
partition p2007 values less than (2008),
partition p2008 values less than (2009),
partition p2009 values less than (2010)
partition p2010 values less than maxvalue
);
2.list分區
復制代碼 代碼如下:
create table t_list(
a int(11),
b int(11)
)(partition by list (b)
partition p0 values in (1,3,5,7,9),
partition p1 values in (2,4,6,8,0)
);
對於innodb和myisam引擎,一條語句插入多條記錄的時候,如果中間有值不能插入,innodb會全部回滾,myisam在錯誤值之前的數據可以插入到表中。對於innodb和myisam引擎,一條語句插入多條記錄的時候,如果中間有值不能插入,innodb會全部回滾,myisam在錯誤值之前的數據可以插入到表中。
3.hash分區
hash分區的目的是將數據均勻的分布到預先定義的各個分區中,保證各分區的數據量大致一致。
復制代碼 代碼如下:
create table t_hash(
a int(11),
b datetime
)partition by hash (YEAR(b)
partitions 4;
hash的分區函數頁需要返回一個整數值。partitions子句中的值是一個非負整數,不加的partitions子句的話,默認為分區數為1。
4.key分區
key分區和hash分區相似,不同在於hash分區是用戶自定義函數進行分區,key分區使用mysql數據庫提供的函數進行分區,NDB cluster使用MD5函數來分區,對於其他存儲引擎mysql使用內部的hash函數,這些函數基於password()一樣的算法。
復制代碼 代碼如下:
create table t_key(
a int(11),
b datetime)
partition by key (b)
partitions 4;
5。columns分區
上面的RANGE、LIST、HASH、KEY四種分區中,分區的條件必須是整形,如果不是整形需要通過函數將其轉換為整形。
mysql-5.5開始支持COLUMNS分區,可視為RANGE和LIST分區的進化,COLUMNS分區可以直接使用非整形數據進行分區。COLUMNS分區支持以下數據類型:
所有整形,如INT SMALLINT TINYINT BIGINT。FLOAT和DECIMAL則不支持。
日期類型,如DATE和DATETIME。其余日期類型不支持。
字符串類型,如CHAR、VARCHAR、BINARY和VARBINARY。BLOB和TEXT類型不支持。
COLUMNS可以使用多個列進行分區。
新增分區
復制代碼 代碼如下:
mysql> ALTER TABLE sale_data
-> ADD PARTITION (PARTITION p201010 VALUES LESS THAN (201011));
Query OK, 0 rows affected (0.36 sec)
Records: 0 Duplicates: 0 Warnings: 0
刪除分區
復制代碼 代碼如下:
--當刪除了一個分區,也同時刪除了該分區中所有的數據。
mysql> ALTER TABLE sale_data DROP PARTITION p201010;
Query OK, 0 rows affected (0.22 sec)
Records: 0 Duplicates: 0 Warnings: 0
分區的合並
下面的SQL,將p201001 - p201009 合並為3個分區p2010Q1 - p2010Q3
復制代碼 代碼如下:
mysql> ALTER TABLE sale_data
-> REORGANIZE PARTITION p201001,p201002,p201003,
-> p201004,p201005,p201006,
-> p201007,p201008,p201009 INTO
-> (
-> PARTITION p2010Q1 VALUES LESS THAN (201004),
-> PARTITION p2010Q2 VALUES LESS THAN (201007),
-> PARTITION p2010Q3 VALUES LESS THAN (201010)
-> );
Query OK, 0 rows affected (1.14 sec)
Records: 0 Duplicates: 0 Warnings: 0