一、 mysql分區簡介
數據庫分區
數據庫分區是一種物理數據庫設計技術。雖然分區技術可以實現很多效果,但其主要目的是為了在特定的SQL操作中減少數據讀寫的總量以縮減sql語句的響應時間,同時對於應用來說分區完全是透明的。
MYSQL的分區主要有兩種形式:水平分區和垂直分區
水平分區(HorizontalPartitioning)
這種形式的分區是對根據表的行進行分區,通過這樣的方式不同分組里面的物理列分割的數據集得以組合,從而進行個體分割(單分區)或集體分割(1個或多個分區)。
所有在表中定義的列在每個數據集中都能找到,所以表的特性依然得以保持。水平分區一定要通過某個屬性列來分割。常見的比如年份,日期等。
垂直分區(VerticalPartitioning)
這種分區方式一般來說是通過對表的垂直划分來減少目標表的寬度,使某些特定的列被划分到特定的分區,每個分區都包含了其中的列所對應所有行。
可以用 showvariables like '%partition%';
命令查詢當前的mysql數據庫版本是否支持分區。
分區的作用:數據庫性能的提升和簡化數據管理
在掃描操作中,mysql優化器只掃描保護數據的那個分區以減少掃描范圍獲得性能的提高。
分區技術使得數據管理變得簡單,刪除某個分區不會對另外的分區造成影響,分區有系統直接管理不用手工干預。
mysql從5.1版本開始支持分區。每個分區的名稱是不區分大小寫。同個表中的分區表名稱要唯一。
二、 mysql分區類型
根據所使用的不同分區規則可以分成幾大分區類型。
RANGE 分區:
基於屬於一個給定連續區間的列值,把多行分配給分區。
LIST 分區:
類似於按RANGE分區,區別在於LIST分區是基於列值匹配一個離散值集合中的某個值來進行選擇。
HASH分區:
基於用戶定義的表達式的返回值來進行選擇的分區,該表達式使用將要插入到表中的這些行的列值進行計算。這個函數可以包含MySQL中有效的、產生非負整數值的任何表達式。
KEY
分區:類似於按HASH分區,區別在於KEY分區只支持計算一列或多列,且MySQL服務器提供其自身的哈希函數。必須有一列或多列包含整數值。
復合分區:
基於RANGE/LIST 類型的分區表中每個分區的再次分割。子分區可以是 HASH/KEY 等類型。
三、mysql分區表常用操作示例
以部門員工表為例子:
1) 創建range分區
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 ); --以員工工資為依據做范圍分區。 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 ); --以year(birthdate)表達式(計算員工的出生日期)作為范圍分區依據。這里最值得注意的是表達式必須有返回值。
2) 創建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分區
HASH分區主要用來確保數據在預先確定數目的分區中平均分布。在RANGE和LIST分區中,必須明確指定一個給定的列值或列值集合應該保存在哪 個分區中;而在HASH分區中,MySQL 自動完成這些工作,你所要做的只是基於將要被哈希的列值指定一個列值或表達式,以及指定被分區的表將要被分割成的分區數量。
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) 創建key分區
按照KEY進行分區類似於按照HASH分區,除了HASH分區使用的用戶定義的表達式,而KEY分區的哈希函數是由MySQL 服務器提供,服務器使用其自己內部的哈希函數,這些函數是基於與PASSWORD()一樣的運算法則。“CREATE TABLE ...PARTITION BY KEY”的語法規則類似於創建一個通過HASH分區的表的規則。它們唯一的區別在於使用的關鍵字是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(范圍哈希)復合分區 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 ); --range- key復合分區 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 key(birthdate) subpartitions 3 ( partition p1 values less than (2000), partition p2 values less than maxvalue ); --list - hash復合分區 CREATE TABLE emp ( empno varchar(20) NOT NULL, empname varchar(20) , deptno int, birthdate date NOT NULL, salary int ) PARTITION BY list (deptno) subpartition by hash(year(birthdate)) subpartitions 3 ( PARTITION p1 VALUES in (10), PARTITION p2 VALUES in (20) ) ; --list - key 復合分區 CREATE TABLE empk ( empno varchar(20) NOT NULL, empname varchar(20) , deptno int, birthdate date NOT NULL, salary int ) PARTITION BY list (deptno) subpartition by key(birthdate) subpartitions 3 ( PARTITION p1 VALUES in (10), PARTITION p2 VALUES in (20) ) ;
6) 分區表的管理操作
刪除分區: alter table emp drop partition p1; 不可以刪除hash或者key分區。 一次性刪除多個分區,alter table emp drop partition p1,p2; 增加分區: alter table emp add partition (partition p3 values less than (4000)); alter table empl add partition (partition p3 values in (40)); 分解分區: Reorganizepartition關鍵字可以對表的部分分區或全部分區進行修改,並且不會丟失數據。分解前后分區的整體范圍應該一致。 alter table te reorganize partition p1 into ( partition p1 values less than (100), partition p3 values less than (1000) ); ----不會丟失數據 合並分區: Merge分區:把2個分區合並為一個。 alter table te reorganize partition p1,p3 into (partition p1 values less than (1000)); ----不會丟失數據 重新定義hash分區表: Alter table emp partition by hash(salary)partitions 7; ----不會丟失數據 重新定義range分區表: Alter table emp partitionbyrange(salary) ( partition p1 values less than (2000), partition p2 values less than (4000) ); ----不會丟失數據 刪除表的所有分區: Alter table emp removepartitioning;--不會丟失數據 重建分區: 這和先刪除保存在分區中的所有記錄,然后重新插入它們,具有同樣的效果。它可用於整理分區碎片。 ALTER TABLE emp rebuild partitionp1,p2; 優化分區: 如果從分區中刪除了大量的行,或者對一個帶有可變長度的行(也就是說,有VARCHAR,BLOB,或TEXT類型的列)作了許多修改,可以使用“ALTER TABLE ... OPTIMIZE PARTITION”來收回沒有使用的空間,並整理分區數據文件的碎片。 ALTER TABLE emp optimize partition p1,p2; 分析分區: 讀取並保存分區的鍵分布。 ALTER TABLE emp analyze partition p1,p2; 修補分區: 修補被破壞的分區。 ALTER TABLE emp repairpartition p1,p2; 檢查分區: 可以使用幾乎與對非分區表使用CHECK TABLE 相同的方式檢查分區。 ALTER TABLE emp CHECK partition p1,p2; 這個命令可以告訴你表emp的分區p1,p2中的數據或索引是否已經被破壞。如果發生了這種情況,使用“ALTER TABLE ... REPAIR PARTITION”來修補該分區。
【mysql分區表的局限性】
1. 在5.1版本中分區表對唯一約束有明確的規定,每一個唯一約束必須包含在分區表的分區鍵(也包括主鍵約束)。
CREATE TABLE emptt ( empno varchar(20) NOT NULL , empname varchar(20), deptno int, birthdate date NOT NULL, salary int , primary key (empno) ) PARTITION BY range (salary) ( PARTITION p1 VALUES less than (100), PARTITION p2 VALUES less than (200) ); --這樣的語句會報錯。MySQL Database Error: A PRIMARY KEY must include allcolumns in the table's partitioning function; CREATE TABLE emptt ( empno varchar(20) NOT NULL , empname varchar(20) , deptno int(11), birthdate date NOT NULL, salary int(11) , primary key (empno,salary) ) PARTITION BY range (salary) ( PARTITION p1 VALUES less than (100), PARTITION p2 VALUES less than (200) ); --在主鍵中加入salary列就正常。
2. MySQL分區處理NULL值的方式
如果分區鍵所在列沒有notnull約束。
如果是range分區表,那么null行將被保存在范圍最小的分區。
如果是list分區表,那么null行將被保存到list為0的分區。
在按HASH和KEY分區的情況下,任何產生NULL值的表達式mysql都視同它的返回值為0。
為了避免這種情況的產生,建議分區鍵設置成NOT NULL。
3. 分區鍵必須是INT類型,或者通過表達式返回INT類型,可以為NULL。唯一的例外是當分
區類型為KEY分區的時候,可以使用其他類型的列作為分區鍵( BLOB or TEXT 列除外)。
4. 對分區表的分區鍵創建索引,那么這個索引也將被分區,分區鍵沒有全局索引一說。
5. 只有RANG和LIST分區能進行子分區,HASH和KEY分區不能進行子分區。
6. 臨時表不能被分區
四、 獲取mysql分區表信息的幾種方法
--1. show create table 表名 --可以查看創建分區表的create語句 --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='test'; --可以查看表具有哪幾個分區、分區的方法、分區中數據的記錄數等信息 --4. explain partitions select語句 --通過此語句來顯示掃描哪些分區,及他們是如何使用的.
五、 分區表性能比較
--1. 創建兩張表: part_tab(分區表),no_part_tab(普通表) CREATE TABLEpart_tab ( c1 int defaultNULL, c2 varchar2(30) default NULL, c3 date not null) PARTITION BYRANGE(year(c3)) (PARTITION p0VALUES LESS THAN (1995), PARTITION p1 VALUESLESS THAN (1996) , PARTITION p2 VALUESLESS THAN (1997) , PARTITION p3 VALUESLESS THAN (1998) , PARTITION p4 VALUES LESS THAN (1999) , PARTITION p5 VALUESLESS THAN (2000) , PARTITION p6 VALUESLESS THAN (2001) , PARTITION p7 VALUESLESS THAN (2002) , PARTITION p8 VALUESLESS THAN (2003) , PARTITION p9 VALUESLESS THAN (2004) , PARTITION p10VALUES LESS THAN (2010), PARTITION p11VALUES LESS THAN (MAXVALUE) ); CREATE TABLE no_part_tab ( c1 int defaultNULL, c2 varchar2(30) default NULL, c3 date not null); --2. 用存儲過程插入800萬條數據 CREATE PROCEDUREload_part_tab() begin declare v int default 0; while v < 8000000 do insert into part_tab values (v,'testingpartitions',adddate('1995-01-01',(rand(v)*36520)mod 3652)); set v = v + 1; end while; end; insert into no_part_tab select * frompart_tab; --3. 測試sql性能 --查詢分區表: selectcount(*) from part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31'; --1 row in set (2.62 sec) --查詢普通表: selectcount(*) from part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31'; --1 row in set (7.33 sec) -- 分區表的執行時間比普通表少70%。 --4. 通過explain語句來分析執行情況 explain select count(*) from part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31'; --+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ --| id |select_type | table | type |possible_keys | key | key_len | ref | rows | Extra | --+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ --| 1 | SIMPLE | part_tab | ALL | NULL | NULL | NULL | NULL | 7980796 | Using where | --+----+-------------+----------+------+---------------+------+---------+------+---------+-------------+ --1 rowin set explain select count(*) from no_part_tab where c3 > date '1995-01-01'and c3 < date '1995-12-31'; --+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+ -- --| id |select_type | table | type |possible_keys | key | key_len | ref | rows | Extra | -- --+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+ -- --| 1 | SIMPLE | no_part_tab | ALL | NULL | NULL | NULL | NULL | 8000206 | Using where | -- --+----+-------------+-------------+------+---------------+------+---------+------+---------+-------------+ -- --1 rowin set 分區表執行掃描了7980796行,而普通表則掃描了8000206行。
ref :https://www.cnblogs.com/pejsidney/p/10074980.html