1. 程式人生 > >問題7:資料庫多表關聯方式

問題7:資料庫多表關聯方式

在關係型資料庫中,多表關聯方式是影響效能最大的技術。為什麼會把mysql定義為中小型資料庫?主要原因是mysql是不支援hash join的。這對多個大表關聯查詢造成效能的瓶頸。因此,在大資料領域,比較少使用mysql作為後臺資料庫。不過,也是有規避的方法,例如我們公司bi專案使用mysql,需要把表設計為寬表,進行反正規化設計,減少多表關聯。雖然單表的資料量大了,但是查詢速度快了非常多,從幾十秒降到1秒左右。1秒對大資料應用是可以接受的,在oltp應用是不可接受。因此,在oltp應用資料庫會進行分庫分表設計,這屬於垂直拆分。按照業務型別進行拆分多個例項和分庫,這屬於水平拆分。目標是實現輕資料庫重業務模式,很多運算需要放到應用程式碼執行。這也是基於資料庫是CS結構,而業務程式碼是分散式結構的屬性。
言歸正傳,下面是對資料庫關聯演算法進行分析,不限於mysql。
多表連線的查詢方式又分為以下幾種:內連線,外連線和交叉連線。外連線又分為:左外連線,右外連線和全外連線。查詢方式需要下面多表關聯演算法來實現:
Nest loop join
巢狀迴圈關聯 適合下面場景,外表是小表,內表是大表,每次外表獲取一條記錄,會在內表進行一次查詢,雖然內表是大表,由於使用高區分度的索引,效率也是非常快。典型的案例維表驅動事實表。
官方文件:

http://dev.mysql.com/doc/refman/5.6/en/nested-loop-joins.html
Block Nested-Loop Join
塊圈套迴圈關聯 從 mysql 5.6開始支援新的關聯方式,每次批量取出部分符合內表的記錄,併發處理與內表關聯,減少關聯次數,提高關聯效率。是圈套迴圈關聯的優化版本。
Multi-Range Read(MRR)
多範圍讀關聯,mysql 5.6開始支援新的關聯方式,將根據輔助索引獲取的結果集根據主鍵進行排序,將亂序化為有序,可以用主鍵順序訪問基表,將隨機讀轉化為順序讀,多頁資料記錄可一次性讀入或根據此次的主鍵範圍分次讀入,以減少IO操作,提高查詢效率。
官方文件:
http://dev.mysql.com/doc/refman/5.6/en/mrr-optimization.html

Batched Key Access(BKA)
批量鍵介面關聯 從mysql 5.6開始支援新的關聯方式,
BKA使用join buffer儲存由join的第一個操作產生的符合條件的資料。 然後BKA演算法構建key來訪問被連線的表,並批量使用MRR介面提交keys到資料庫儲存引擎去查詢查詢。提交keys之後,MRR使用最佳的方式來獲取行並反饋給BKA .
Sort Merge join
排序混合關聯 mysql目前不支援,oracle,sql server,postgresql支援。需要首先對兩個表按照關聯的欄位進行排序,分別從兩個表中取出一行資料進行匹配,如果合適放入結果集;不匹配將較小的那行丟掉繼續匹配另一個表的下一行,依次處理直到將兩表的資料取完。若是關聯欄位有高區分度的索引,則效率也是非常高。
Hash join
雜湊關聯 mysql目前不支援,oracle,postgresql支援。下面詳細描述oracle的hash join實現方法:Oracle依據hash_area_size/db_block_size/_hash_multiblock_io_count決定hash partition數量,hash表由若干hash partition組成,而每個partition都包含多個hash bucket。表small和big,前者會被選為驅動表,假定其結果集為s,後者為b;驅動表和被驅動表都是最多隻被訪問一次。雜湊表連線的表無需要排序,但是他在做連線之前做雜湊運算的時候,會用到HASH_AREA_SIZE來建立雜湊表。雜湊連線不適用於的連線條件是:不等於<>,大於>,小於<,小於等於<=,大於等於>=,like。雜湊連線索引列在表連線中無特殊要求,與單表情況無異。
目前mysql在該方面相對來說是較弱的,我們應該取長補短,使用mysql效能高的地方,減少使用mysql短板的技術。