mysql分区(partition)
分區和性能
數據庫的應用分為兩類:
1、OLTP 在線事務處理,如blog,電子商務,網絡游戲
2、OLAP 在線分析處理,如數據倉庫,數據集市
3、對于OLAP的應用,分區的確是可以很好地提高查詢的性能,因為OLAP應用大多數查詢需要頻繁地掃描一張很大的表。假設有一張1億行的表,其中有一個時間戳屬性列,用戶查詢需要從這張表中獲取一年的數據,如果按時間進行分區,則只需要掃描相應的分區即可。
4、但是對于OLTP的應用,分區應該非常小心,在這種應用下,通常不可能會獲取一張達標中10%的數據,大部分都是通過索引返回幾條記錄即可。根據B+樹索引的原理可知,對于一張大表,一般的B+樹需要2~3次磁盤IO。因此B+樹可以很好地完成操作,不需要分區的幫助。并且設計不好的分區會帶來嚴重的性能問題,
比如1000行的表,對主鍵做10個hash分區,這樣每個分區就只有100w的數據了,因此查詢應該變得快了,但是有沒有考慮這樣一種情況:100w和1000w行的數據本身構成B+樹層次都是一樣的,可能是2層。那么走主鍵分區的索引并不會帶來性能的提高。如果1000wB+樹的高度是3層,100w的是2層,那么按照主鍵索引可以避免1次IO,從而提高了效率。這是對主鍵索引進行查詢,但是如果對其他列進行查詢,這時需要掃描10個分區,每個分區的開銷是2次IO,一共20次IO。而對原來的單表設計,對于列的查詢只有2~3次IO。
因此,對于使用innodb存儲引擎作為OLTP應用的表在試用分區時應該十分小心,設計時確認數據的訪問模式,否則在OLTP應用下分區可能不僅不會帶來查詢速度的提高,反而可能會是你的應用執行的更慢。
分區類型
range,list,hash,key這四種分區中,分區的條件是:數據必須是整型,如果不是整型,那應該通過函數將其轉化為整型(如:YEAR(),TO_DAYS(),MONTH()等函數)。
range分區
create table sales ( money int unsigned not null, date datetime ) engine=innodb partition by range (TO_DAYS(date)) ( partition p201001 values less than (TO_DAYS('2010-02-01')), partition p201002 values less than (TO_DAYS('2010-03-01')), partition p201003 values less than (TO_DAYS('2010-04-01')) );
對于range分區的查詢,優化器只能對YEAR(),TO_DAYS(),TO_SECONDS(),UNIX_TIMESTAMP()這類函數進行優化分區。
list分區
create table t1( a int, b int ) engine=innodb partition by list(b) ( partition p0 values in (1,3,5,7,9), partition p1 values in (0,2,4,6,8) );
list分區,如果是插入多行數據時,有不符合分區規則情況下,myisam存儲引擎會存放符合分區規則的,而innodb會把它看成一個事務,不會插入數據,會報錯
hash分區
--- hash分區 是將數據均勻的分配到預先定義的各個分區中,保證各分區的數量大致都是一樣的 --- 要使hash分區來分割一個表,要在create table 語句上添加“partition by hash(expr)”子句,其中expr是一個返回一個整數的表達式,它可以僅僅是字段類型為mysql整型的列名。 --- 此外用戶很可能需要在后面再添加一個"partitions num"子句,其中num是一個非負整數,表示表將要分割成分區的數量,沒有這個子句,默認是1 create table t2( a int, b datetime ) engine=innodb partition by hash (year(b)) partitions 4;
hash分區是取模算法:如b為2010-04-01時 mod(year('2010-04-01'), 4) = mod(2010, 4) = 2 因此記錄會被放入分區p2中。
另一種hash分區——linear hash(hash算法不同)
這種分區算法的優點是:增加、刪除、合并、和拆分分區將變得更加快捷,有利于含有處理大量數據的表。
缺點是:與使用hash分區得到的數據分布相比,各個分區間數據的分布可能不大均勻。
分區算法是:同樣是2010-04-01
1、取大于分區數量num=4的下一個2的冪值V,V = power(2, ceiling(log(2, NUM))) = 4;即log以2為底num的指數作為2的冪值。2^log(2, num)
2、所在分區N = YEAR('2010-04-01') & (V - 1) = 2
key分區
key分區和hash分區相似,不同之處在于hash分區使用用戶定義的函數進行分區,key分區使用MySQL數據庫提供的函數進行分區。對于NDB cluster引擎,MySQL數據庫使用MD5函數分區,對于其他的數據庫引擎,MySQL數據庫使用其內部的哈希函數,這些函數基于與password()一樣的運算法則
create table t4( a int, b datetime )engine=innodb partition by key (b) partitions 4;在key分區中使用關鍵字linear和在hash分區中使用具有相同的效果,分區標號是通過2的冪算法(powers-of-two)得到的,而不是通過模數算法。
columns分區
MySQL5.5版本開始支持columns分區,可以看做range分區和list分區的一種進化。
columns分區可以直接使用非整型的數據進行分區,分區根據類型直接比較而得,不需要轉化為整型。
columns分區支持以下的數據類型:
1、所有的整數類型,如int,smallint,tinyint,mediumint,bigint。float和decimal則不予支持
2、日期類型,如date和datetime。其余的日期類型不予支持。
3、字符串類型,如char,varchar,binary和varbinary。blob和text類型不予支持。
range columns
range columns 分區可以對多個列的值進行分區。
create table t5_rcx( a int, b int, c char(3), d int )engine=innodb partition by range columns (a,d,c) ( partition p0 values less than (5, 10, 'ggg'), partition p1 values less than (10, 20, 'mmm'), partition p2 values less than (15, 20, 'sss'), partition p3 values less than (maxvalue, maxvalue, maxvalue) );list columns
中文也可以 create table t6( first_name varchar(25), last_name varchar(25), street_1 varchar(30), street_2 varchar(30), city varchar(15), renewal date )engine=innodb partition by list columns (city) ( partition pRegion_1 values in ('北京','上海','廣州'), partition pRegion_2 values in ('武漢','鄭州','成都') );子分區
子分區是指在分區的基礎上再進行分區,也稱該分區為復合分區。MySQL允許在range和list的分區上再進行hash和key的子分區。
create table ts( a int, b date )engine=innodb partition by range (YEAR(b)) subpartition by hash(TO_DAYS(b)) subpartitions 2 ( partition p0 values less than (1990), partition p1 values less than (2000), partition p2 values less than maxvalue ); b列進行range分區,又進行了一次hash分區,分區的數量是(3 x 2 = 6)我們也可以使用subpartition語法顯示的指出各個子分區的名字:
create table dspy_sub_name( a int, b date )engine=innodb partition by range (YEAR(b)) subpartition by hash (TO_DAYS(b)) ( partition p0 values less than (2009) ( subpartition s0, subpartition s1 ), partition p1 values less than (2010) ( subpartition s2, subpartition s3 ), partition p2 values less than maxvalue ( subpartition s4, subpartition s5 ) );子分區建立需要注意以下幾個問題:
1、每個子分區的數量必須相同
2、要在一個分區表的任何分區上使用subpartition明確定義任何子分區,就必須定義所有的子分區。
3、每個subpartition子句必須包括子分區的一個名字
4、子分區的名字必須是唯一的。
子分區可以用于特別大的表,在多個磁盤間分別分配數據和索引。假設有6個磁盤,分別為/disk0,/disk1,/disk2等,現在考慮下面的例子:
create table ts1( a int, b date )engine=innodb partition by range (YEAR(b)) subpartition by hash (TO_DAYS(b)) ( partition p0 values less than (2009) ( 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 (2010) ( subpartition s2 DATA DIRECTORY = '/disk2/data' INDEX DIRECTORY = '/disk2/idx', subpartition s3 DATA DIRECTORY = '/disk3/data' INDEX DIRECTORY = '/disk3/idx' ), partition p2 values less than (2011) ( subpartition s4 DATA DIRECTORY = '/disk4/data' INDEX DIRECTORY = '/disk4/idx', subpartition s5 DATA DIRECTORY = '/disk5/data' INDEX DIRECTORY = '/disk5/idx' ) );由于innodb存儲引擎使用表空間自動的進行數據和索引的管理,因此會忽略DATA DIRECTORY 和INDEX DIRECTORY語法,因此上述分區表的數據和索引文件的分開放置對其是無效的。
分區中的null值
mysql數據庫允許對null值做分區。MySQL數據庫的分區總是把null值看做是小于任何一個非null值,這和MySQL數據庫中處理null值得order by操作是一樣的。因此對于不同的分區類型,MySQL數據庫對于null值的處理也是不相同的。
1、對于range分區,如果向分區中插入null值,則MySQL數據庫會將該值放入最左邊的分區,另外注意的是如果刪除最左邊的分區,則會刪除該分區的記錄包括null值的記錄
2、list分區下要使用null值,則必須顯示地指出哪個分區中放入null值,否則會報錯。
3、hash和key分區對于null的處理方式和range分區、list分區不一樣。任何分區的函數都會講含有null值得記錄返回為0
在表和分區間交換數據
MySQL5.6開始支持alter table?table_name?exchange partition?partition_name?with table?table_name的語法。該語法允許分區或子分區中的數據與另一個非分區的表中的數據進行交換。如果紛紛去表中的數據為空,那么相當于將分區中的數據移動到非分區表中。若分區表中的數據為空,則相當于將外部表中的數據導入到分區中。
要使用這個語法要滿足以下條件:
1、要交換的表必須和分區表有相同的表結構,但是要交換的表不能含有分區
2、在非分區表中的數據必須在交換的分區定義內
3、被交換的表中不能含有外鍵或者其他的表含有對該表的外鍵引用
4、用戶除了需要alter,insert,create權限外,還需要有drop權限
另外,有兩個小細節需要注意:
1、使用該語句時不會觸發交換表和被交換表上的觸發器
2、auto_increment列將被重置
結果:
總結
以上是生活随笔為你收集整理的mysql分区(partition)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多媒体计算机的概念是,多媒体计算机的基本
- 下一篇: linux cmake编译源码,linu