1、並行資料庫
1.1、並行資料庫的體系結構
並行機的出現,催生了並行資料庫的出現,不對,應該是關係運算本來就是高度可並行的。對資料庫系統效能的度量主要有兩種方式:(1)吞吐量(Throughput),在給定的時間段裡所能完成的任務數量;(2)響應時間(Response time),單個任務從提交到完成所需要的時間。對於處理大量小事務的系統,通過並行地處理許多事務可以提高它的吞吐量。對於處理大事務的系統,通過並行的執行事務的子任務,可以縮短系統晌應時間。
並行機有三種基本的體系結構,相應的,並行資料庫的體系結構也可以大概分為三類:
- 共享記憶體(share memeory):所有處理器共享一個公共的儲存器;
- 共享磁碟(share disk):所有處理器共享公共的磁碟;這種結構有時又叫做叢集(cluster);
- 無共享(share nothing):所有處理器既不共享記憶體,也不共享磁碟。
如圖所示:
1.1.1、 共享記憶體
該結構包括多個處理器、一個全域性共享的記憶體(主儲存器)和多個磁碟儲存,各個處理器通過高速通訊網路(Interconnection Network)與共享記憶體連線,並均可直接訪問系統中的一個、多個或全部的磁碟儲存,在系統中,所有的記憶體和磁碟儲存均由多個處理器共享。
這種結構的優點在於,處理器之間的通訊效率極高,訪問記憶體的速度要比訊息通訊機制要快很多。這種結構的缺點在於,處理器的規模不能超過32個或者64個,因為匯流排或互邊網路是由所有的處理器共享,它會變成瓶頸。當處理器數量到達某一個點時,再增加處理器已經沒有什麼好處。
共享記憶體結構通常在每個處理器上有很大的快取記憶體,從而減少對記憶體的訪問。但是,這些快取記憶體必須保持一致,也就是快取一致性(cache-coherency)的問題。
1.1.2、 共享磁碟
該結構由多個具有獨立記憶體(主儲存器)的處理器和多個磁碟儲存構成,各個處理器相互之間沒有任何直接的資訊和資料的交換,多個處理器和磁碟儲存由高速通訊網路連線,每個處理器都可以讀寫全部的磁碟儲存。
共享磁碟與共享記憶體結構相比,有以下一些優點:(1)每個處理器都有自己的儲存器,儲存匯流排不再是瓶頸;(2)以一種較經濟的方式提供了容錯性(fault tolerence),如果一個處器發生故障,其它處理器可以代替工作。
該結構的主要問題不是在於可擴充套件性問題,雖然儲存匯流排不是瓶頸,但是,與磁碟之間的連線又成了瓶頸。
執行Rdb的DEC叢集是共享磁碟的體系結構的早期商用化產品之一(DEC後來被Compaq公司收購,再後來,Oracle又從Compaq手中取得Rdb,發展成現在的Oracle RAC)。
1.1.3、 無共享
該結構由多個完全獨立的處理節點構成,每個處理節點具有自己獨立的處理器、獨立的記憶體(主儲存器)和獨立的磁碟儲存,多個處理節點在處理器級由高速通訊網路連線,系統中的各個處理器使用自己的記憶體獨立地處理自己的資料。
這 種結構中,每一個處理節點就是一個小型的資料庫系統,多個節點一起構成整個的分散式的並行資料庫系統。由於每個處理器使用自己的資源處理自己的資料,不存 在記憶體和磁碟的爭用,提高的整體效能。另外這種結構具有優良的可擴充套件性——只需增加額外的處理節點,就可以以接近線性的比例增加系統的處理能力。
這種結構中,由於資料是各個處理器私有的,因此係統中資料的分佈就需要特殊的處理,以儘量保證系統中各個節點的負載基本平衡,但在目前的資料庫領域,這個資料分佈問題已經有比較合理的解決方案。
由於資料是分佈在各個處理節點上的,因此,使用這種結構的並行資料庫系統,在擴充套件時不可避免地會導致資料在整個系統範圍內的重分佈(Re-Distribution)問題。
Shared-Nothing結構的典型代表是Teradata(並行資料庫的先驅),值得一提的是,MySQL NDB Cluster也使用了這種結構。
1.2、I/O並行(I/O Parallelism)
I/O並行的最簡單形式是通過對關係劃分,放置到多個磁碟上來縮減從磁碟讀取關係的時間。並行資料庫中資料劃分最通用的形式是水平劃分(horizontal portioning),一個關係中的元組被劃分到多個磁碟。
1.2.1、常用劃分技術
假定將資料劃分到n個磁碟D0,D1,…,Dn中。
(1) 輪轉法(round-bin)。對關係順序掃描,將第i個元組儲存到標號為Di%n的磁碟上;該方式保證了元組在多個磁碟上均勻分佈。
(2) 雜湊劃分(hash partion)。選定一個值域為{0, 1, …,n-1}的雜湊函式,對關係中的元組基於劃分屬性進行雜湊。如果雜湊函式返回i,則將其儲存到第i個磁碟。
(3) 範圍劃分(range partion)。
由於將關係儲存到多個磁碟,讀寫時能同時進行,劃分(partion)能大大提高系統的讀寫效能。資料的存取可以分為以下幾類:
(1) 掃描整個關係;
(2) 點查詢(point query),如name = “hustcat”;
(3) 範圍查詢(range query),如 20 < age < 30。
不同的劃分技術,對這些存取型別的效率是不同的:
- 輪轉法適合順序掃描關係,對點查詢和範圍查詢的處理較複雜。
- 雜湊劃分特別適合點查詢,速度最快。
- 範圍劃分對點查詢、範圍查詢以及順序掃描都支援較好,所以適用性很廣。但是,這種方式存在一個問題——執行偏斜(execution skew),也就是說某些範圍的元組較多,使得大量的I/O出現在某幾個磁碟。
1.3、查詢間並行(interquery parallism)
查詢間並行指的是不同的查詢或事務間並行的執行。這種形式的並行可以提高事務的吞吐量,然而,單個事務並不能執行得更快(即響應時間不能減少)。查詢間的並行主要用於擴充套件事務處理系統,在單位時間內能夠處理更多的事務。
查詢間並行是資料庫系統最易實現的一種並行,在共享記憶體的並行系統(如SMP)中尤其這樣。為單處理器設計的資料庫系統可以不用修改,或者很少修改就能用到共享記憶體的體系結構。
在共享磁碟和無共享的體系結構中,實現查詢間並行要更復雜一些。各個處理需要協調來進行封鎖、日誌操作等等,這就需要處理器之間的傳遞訊息。並行資料庫系統必須保證兩個處理器不會同時更新同一資料。而且,處理器訪問資料時,系統必須保證處理器快取的資料是最新的資料,即快取一致性問題。
1.4、查詢內並行(intraquery parallism)
查詢內並行是指單個查詢要在多個處理器和磁碟上同時進行。為了理解,來考慮一個對某關係進行排序的查詢。假設關係已經基於某個屬性進行了範圍劃分,儲存於多個磁碟上,並且劃分是基於劃分屬性的。則排序操作可以如下進行:對每個分割槽並行的排序,然後將各個已經有序的分割槽合併到一起。
單個查詢的執行可以有兩種並行方式:
(1) 操作內並行(Intraoperation parallism):通過並行的執行每一個運算,如排序、選擇、連線等,來加快一個查詢的處理速度。
(2) 操作間並行(Interoperation parallism):通過並行的執行一個查詢中的多個不同的運算,來加速度一個查詢的處理速度。
注意兩者間的區別,前者可以認為多個處理器同時執行一個運算,而後者是多個處理器同時執行不同的運算。
這兩種形式之間的並行是互相補充的,並且可以同時存在於一個查詢中。通常由於一個查詢中的運算數目相對於元組數目是較小的,所以當並行度增加時,第一種方式取得的效果更顯著。
2、MySQL的分割槽(partion)
2.1、MySQL分割槽概述
在MySQL中,InnoDB儲存引擎長期支援表空間的概念,並且MySQL伺服器甚至在分割槽引入之前,就能配置為儲存不同的資料庫使用不同的物理路徑。分割槽(partion)更進一步,它允許你通過設定各種規則將一個表的各個分割槽跨檔案系統儲存。實際上,不同位置的不同表分割槽是作為一個單獨的表來儲存的。使用者所選擇的、實現資料分割的規則被稱為分割槽函式(partioning function),這在MySQL中它可以是模數,或者是簡單的匹配一個連續的數值區間或數值列表,或者是一個內部HASH函式,或一個線性HASH函式。
最常見是的水平分割槽(horizontal partitioning),也就是將表的不同的元組分配到不同的物理分割槽上。目前,MySQL 5.1還不支援垂直分割槽(vertical partitioning),即將表的不同列分配到不同的物理分割槽。你可以使用MySQL支援的大多數儲存引擎來建立表的分割槽,在MySQL 5.1中,同一個表的各個分割槽必須使用相同的儲存引擎,比如,你不能對一個分割槽使用MyISAM,而對另一個分割槽使用InnoDB。但是,你可以對同一個資料庫的不同的表使用不同的儲存引擎。
要為某個分割槽表配置一個專門的儲存引擎,必須且只能使用[STORAGE] ENGINE 選項,這如同為非分割槽表配置儲存引擎一樣。但是,必須記住[STORAGE] ENGINE(和其他的表選項)必須列在用在CREATE TABLE語句中的其他任何分割槽選項之前。下面的例子給出了怎樣建立一個通過HASH分成6個分割槽、使用InnoDB儲存引擎的表:
注:分割槽必須對一個表的所有資料和索引;不能只對資料分割槽而不對索引分割槽,反之亦然,同時也不能只對表的一部分進行分割槽。
分割槽對資料庫管理系統實現並行處理有著重要的影響,如果對資料進行分割槽,則很容易進行並行處理,但是,MySQL還沒有充分利用分割槽的這種並行優勢,而這也是它改進的方向 (這種分治思想深深的影響著平行計算,而且在平行計算方面具有天然優勢)。MySQL的分割槽,會給系統帶來以下一些優點:
- 與單個磁碟或檔案系統分割槽相比,單個表可以儲存更多的資料。
- 對於那些已經失去儲存意義的資料,通常可以通過刪除與那些資料有關的分割槽,很容易地刪除那些資料。相反地,在某些情況下,新增新資料的過程又可以通過為那些新資料專門增加一個新的分割槽,來很方便地實現。
- 對於帶Where的條件查詢語句,可以得到更大的優化;只需要查詢某些分割槽,而不用掃描全部分割槽。
- 還有其它一些優點,不過MySQL 5.1還不支援:
- 一些聚合函式,比如SUM() 和COUNT(),能夠很容易的並行執行;
- 通過並行I/O,可以大大提高查詢的吞吐量。
注:實際上,分割槽不論是對I/O並行,還是查詢內並行,都有著重要的影響。只不過MySQL在這方面做得還不夠多(不過,正在改進),而Oracle對於查詢內並行,做了很多工作。
2.2、分割槽型別
MySQL 5.1中可用的分割槽型別包括:
- RANGE分割槽(portioning):根據列值所屬的範圍區間,將元組分配到各個分割槽。
- LIST分割槽:類似於按RANGE分割槽,區別在於LIST分割槽是基於列值匹配一個離散值集合中的某個值來進行選擇。
- HASH分割槽:根據使用者定義的函式的返回值來進行選擇的分割槽,該表示式使用將要插入到表中的這些行的列值進行計算。這個函式可以包含MySQL 中有效的、產生非負整數值的任何表示式。
- KEY分割槽:類似於按HASH分割槽,區別在於KEY分割槽只支援計算一列或多列,且MySQL 伺服器提供其自身的雜湊函式。
2.2.1、範圍分割槽
範圍分割槽是通過計算表示式的值所屬的範圍區間,對元組進行分割槽。這些區間要求連續且不能相互重疊,使用VALUES LESS THAN操作符來進行定義。在下面的幾個例子中,假定你建立了一個如下的一個表,該表儲存有20家音像店的職員記錄,這20家音像店的編號從1到20。
你可以根據需要對該表進行各種分割槽,比如,你可以通過store_id來進行分割槽:
很容易確定資料(72, ‘Michael’, ‘Widenius’, ‘1998-06-25’, NULL, 13)被插入分割槽p2;但是,如果一條資料的store_id = 21,會怎麼樣呢?由於沒有規則處理大於20的情況,所以伺服器會報錯。你可以通過如下方式來處理這種情況:
MAXVALUE 表示最大的可能的整數值。現在,store_id 列值大於或等於16(定義了的最高值)的所有行都將儲存在分割槽p3中。在將來的某個時候,當商店數已經增長到25, 30, 或更多 ,可以使用ALTER TABLE語句為商店21-25, 26-30,等等增加新的分割槽
RANGE分割槽在如下場合特別有用:
(1) 當需要刪除“舊的”資料時。 在上面的例子中,你只需簡單地使用 “ALTER TABLE employees DROP PARTITION p0;”來刪除所有在1991年前就已經停止工作的僱員相對應的所有行。對於有大量行的表,這比執行一個如“DELETE FROM employees WHERE YEAR(separated) <= 1990;”這樣的一個DELETE查詢要有效得多。
(2) 經常依賴於分割槽屬性進行查詢。例如,當執行一個如“SELECT COUNT(*) FROM employees WHERE YEAR(separated) = 2000 GROUP BY store_id;”這樣的查詢時,MySQL可以很迅速地確定只有分割槽p2需要掃描,這是因為餘下的分割槽不可能包含有符合該WHERE子句的任何記錄。注:這種優化還沒有在MySQL 5.1源程式中啟用,但是,有關工作正在進行中。
範圍分割槽的缺點就是容易出現執行偏斜,這會影響系統效能。
2.2.2、HASH分割槽
HASH分割槽主要用來確保資料在預先確定數目的分割槽中平均分佈。在RANGE和LIST分割槽中,必須明確指定一個給定的列值或列值集合應該儲存在哪個分割槽中;而在HASH分割槽中,MySQL 自動完成這些工作,你所要做的只是基於將要被雜湊的列值指定一個列值或表示式,以及指定被分割槽的表將要被分割成的分割槽數量。
你可以通過要在CREATE TABLE 語句上新增一個“PARTITION BY HASH (expr)”子句,其中“expr”是一個返回一個整數的表示式。它可以僅僅是欄位型別為MySQL 整型的一列的名字。此外,你很可能需要在後面再新增一個“PARTITIONS num”子句,其中num 是一個非負的整數,它表示表將要被分割成分割槽的數量。比如:
如果沒有PARTITIONS語句,預設分割槽數為1。但是,PARTITIONS後面沒有數字,系統會報錯。
相對於範圍分割槽,HASH分割槽更可能保證資料均衡分佈。
2.2.3、子分割槽(Subpartitioning)
子分割槽,也叫做複合分割槽(composite partitioning),是對分割槽表的每個分割槽的進一步分割。例如,
表ts 有3個RANGE分割槽。這3個分割槽中的每一個分割槽——p0, p1, 和 p2 ——又被進一步分成了2個子分割槽。實際上,整個表被分成了3 * 2 = 6個分割槽。但是,由於PARTITION BY RANGE子句的作用,這些分割槽的頭2個只儲存“purchased”列中值小於1990的那些記錄。
在MySQL 5.1中,對於已經通過RANGE或LIST分割槽了的表再進行分割槽。子分割槽既可以使用HASH希分割槽,也可以使用KEY分割槽。
為了對個別的子分割槽指定選項,使用SUBPARTITION 子句來明確定義子分割槽也是可能的。例如,建立在前面例子中給出的同一個表的、一個更加詳細的方式如下:
一些注意點:
(1) 每個分割槽的子分割槽數必須相同;
(2) 如果在一個分割槽表上的任何分割槽上使用SUBPARTITION 來明確定義任何子分割槽,那麼就必須定義所有的子分割槽;
(3) 每個SUBPARTITION子句必須包含一個子分割槽的名稱;
(4) MySQL 5.1.7及之前的版本,每個分割槽的子分割槽的名稱必須唯一,但是在整個表中,沒有必要唯一。從MySQL 5.1.8開始,子分割槽的名稱在整個表中都必須唯一。
子分割槽可以用於特別大的表,在多個磁碟間分配資料和索引。假設有6個磁碟,分別為/disk0, /disk1, /disk2等,對於如下例子:
3、體驗分割槽
下面通過例子來體驗分割槽:
(1)建立如下分割槽表:
(2)建立一個不分割槽的表:
(3) 建立一個生成8000000行資料的儲存過程:
(4) 呼叫儲存過程,生成資料:
(5)
資料準備好了,下面開始測試:
(6)
速度差異很明顯;下面看一下查詢計劃:
(7)
附SQL語句:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
程式碼Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/--> 1 CREATE TABLE part_tab ( c1 int default NULL, c2 varchar(30) default NULL, c3 date default NULL ) engine=myisam PARTITION BY RANGE (year(c3)) ( PARTITION p0 VALUES LESS THAN (1995), PARTITION p1 VALUES LESS THAN (1996) , PARTITION p2 VALUES LESS THAN (1997) , PARTITION p3 VALUES LESS THAN (1998) , PARTITION p4 VALUES LESS THAN (1999), PARTITION p5 VALUES LESS THAN (2000) , PARTITION p6 VALUES LESS THAN (2001) , PARTITION p7 VALUES LESS THAN (2002) , PARTITION p8 VALUES LESS THAN (2003) , PARTITION p9 VALUES LESS THAN (2004) , PARTITION p10 VALUES LESS THAN (2010), PARTITION p11 VALUES LESS THAN MAXVALUE ); create table no_part_tab (c1 int(11) default NULL, c2 varchar(30) default NULL, c3 date default NULL ) engine=myisam; delimiter // CREATE PROCEDURE load_part_tab() begin declare v int default 0; while v < 8000000 do insert into part_tab(c1,c2,c3) values (v,'testing partitions',adddate('1995-01-01',(rand(v)*36520) mod 3652)); set v = v + 1; end while; end // delimiter ; call load_part_tab(); explain select count(*) from no_part_tab where c3 > date '1995-01-01' and c3 < date '1995-12-31'; explain select count(*) from part_tab where c3 > date '1995-01-01' and c3 < date '1995-12-31'; CREATE TABLE part_tab2 ( c1 int default NULL ) engine=myisam PARTITION BY RANGE (c1) ( PARTITION p0 VALUES LESS THAN (5), PARTITION p1 VALUES LESS THAN (10), PARTITION p2 VALUES LESS THAN MAXVALUE ); insert into part_tab2 values(2),(3); |
主要參考:《MySQL Manual》