行存儲和列存儲小介紹

、定義

 

1.1定義

Sybase在2004年左右就推出了列存儲的Sybase IQ數據庫系統,主要用於在線分析、數據挖掘等查詢密集型應用。列存儲,縮寫爲DSM,相對於NSM(N-ary storage model),其主要區別在於:

DSM將所有記錄中相同字段的數據聚合存儲;

NSM將每條記錄的所有字段的數據聚合存儲;

其實列存儲並不是什麼新概念,早在1985年SIGMOD會議上就有文章” A decomposition storage model”對DSM(decomposition storage model)做了比較詳細的介紹,而Sybase更在2004年左右就推出了列存儲的Sybase IQ數據庫系統(見200年VLDB文章” Sybase iq multiplex - designed for analytics”),主要用於在線分析、數據挖掘等查詢密集型應用。

列存儲,縮寫爲DSM,相對於NSM(N-ary storage model),其主要區別在於,DSM將所有記錄中相同字段的數據聚合存儲,而NSM將每條記錄的所有字段的數據聚合存儲,如下圖所示:

clip_image002

列存儲有什麼優點?

就我目前比較膚淺的理解,列存儲的主要優點有兩個:

1) 每個字段的數據聚集存儲,在查詢只需要少數幾個字段的時候,能大大減少讀取的數據量,據C-Store, MonetDB的作者調查和分析,查詢密集型應用的特點之一就是查詢一般只關心少數幾個字段,而相對應的,NSM中每次必須讀取整條記錄;

2) 既然是一個字段的數據聚集存儲,那就更容易爲這種聚集存儲設計更好的壓縮/解壓算法。

列存儲適合用在什麼場合?

OLAP,數據倉庫,數據挖掘等查詢密集型應用。當然,列存儲數據庫並不是說完全不能進行更新操作,其實它們的更新操作性能並不是很差,一般也夠用,但是一方面不如自己的查詢性能,另外一方面也不如Oracle這種專門搞OLTP的數據庫,所以一般就不提這個。

列存儲不適合用在什麼場合?

相對來說,不適合用在OLTP,或者更新操作,尤其是插入、刪除操作頻繁的場合。

爲啥上世紀80年代就出現的概念現在又重新炒起來了呢?

2005年VLDB有篇文章(“One Size Fits All - An Idea Whose Time Has Come and Gone”),就是那個老牛M. Stonebraker寫的,明確指出,時代變了,指望一個數據庫產品就統一天下的日子已經一去不復還了。於是,這個老牛在2005年左右做了C-Store,一個列存儲的數據庫原型系統,在VLDB, SIGMOD等頂級國際會議上灌了幾桶水後,


1.2優點

列存儲的主要優點有兩個:

1) 每個字段的數據聚集存儲,在查詢只需要少數幾個字段的時候,能大大減少讀取的數據量,據C-Store, MonetDB的作者調查和分析,查詢密集型應用的特點之一就是查詢一般只關心少數幾個字段,而相對應的,NSM中每次必須讀取整條記錄;

2) 既然是一個字段的數據聚集存儲,那就更容易爲這種聚集存儲設計更好的壓縮/解壓算法。

1.3場合

列存儲適合用在什麼場合?

  OLAP,數據倉庫,數據挖掘等查詢密集型應用。當然,列存儲數據庫並不是說完全不能進行更新操作,其實它們的更新操作性能並不是很差,一般也夠用,但是一方面不如自己的查詢性能,另外一方面也不如Oracle這種專門搞OLTP的數據庫,所以一般就不提這個。

列存儲不適合用在什麼場合?

相對來說,不適合用在OLTP,或者更新操作,尤其是插入、刪除操作頻繁的場合。

1.4發展史

  有篇文章(“One Size Fits All - An Idea Whose Time Has Come and Gone”),就是那個老牛M. Stonebraker寫的,明確指出,時代變了,指望一個數據庫產品就統一天下的日子已經一去不復還了。於是,這個老牛在2005年左右做了C-Store,一個列存儲的數據庫原型系統,在VLDB, SIGMOD等頂級國際會議上灌了幾桶水後,拉了一夥人出去開了個公司叫Vertica,將其商業化,專注於數據倉庫、在線分析等市場,最近貌似還挺紅火的;順便說一下,爲了貫徹上面的思想,這個老牛在同一時期又做了H-Store,一個主內存數據庫原型系統,沒怎麼灌水就又招呼了一幫人開了個公司叫VoltDB,將其商業化,專注於聯機事務處理。

M. Stonebraker在上世紀70年代帶頭開展關係數據庫管理系統的實現工作,做出來了Ingres,其中灌水無數,從這個原型系統基礎上產生了很多商業數據庫軟件,包括 Sybase、Microsoft SQL Server、NonStop SQL、Informix 等,而所謂的最先進的開源數據庫系統PostgreSQL也是Ingres的一個後繼分支。

二、sysbase iq 列存儲介紹

Sybase IQ —— 革命性的產品。Sybase的數據倉庫方法從根本上不同於其他的關係型數據庫提供商。Sybase認爲,傳統的關係型方法以及ROLAP方法效率很低,要想獲得足夠的性能,必須通過高額的成本,在額外的硬件、軟件、資源、錢、時間上進行大量投資,否則不可能達到。因此Sybase已經開發了一個新的關係型數據庫——逆向關係型數據庫可能是對此最好的解釋,它使用一個傳統的關係型結構以及類似的非常熟悉的術語,但是卻是基於列的,而非基於行的。

我們開始審視Sybase IQ時,我們正是從此點開始,Sybase對其使用列方法的好處所作的論述“相當令人信服”。然而,通過對數據倉庫不斷增加需求、迅猛增長的來自Web的數據與用戶所帶來的分析和報表(更不必提即將到來的RFID應用),以及客戶的經驗等等,我們現在可以證明,Sybase IQ提供了一個遠比那些傳統的關係型供應商更優越的方法。

2.1列存儲

不同於傳統的關係型數據庫,其數據在表中是按行存儲的,Sybase IQ是通過表中的列來存儲與訪問數據的。儘管這種方式很明顯的不太適合於交易環境,在交易環境中,一個事務與一行數據有效對應,而在查詢進程環境中,很顯然,查詢是基於特定的列來選擇的。

列方式所帶來的重要好處之一就是,由於查詢中的選擇規則是通過列來定義的,因此整個數據庫是自動索引化的。事實上,情況並不象上述的這樣簡單,Sybase IQ有各種方法支持基於列的索引,我們將在下面就此討論。

使用列方法的另一個結果就是,Sybase IQ在壓縮方面比傳統的關係型數據庫更加有效(根據Sybase所稱,效果可達5倍之好)。這個原因,無疑說,是由於同一列中的所有數據域有相同的數據類型。因此,每一列都可以爲優化的效率與檢索進行壓縮。相比來講,基於行的存儲,各個不同的域擁有各不相同的數據類型,這非常適合於交易進程。在這樣的環境中,不斷變換理想的壓縮算法是不可行的,這意味着任何壓縮都將可能是一種最低通用的規則。

基於列的方法的另一個重要優勢完全基於所有讀出的數據量。無論何時你從傳統的數據庫中訪問數據,你需要讀出完整的每一行,而不管你實際所感興趣的是哪些域。實際上,這可能意味着讀300個字節的數據僅僅檢索20個字符的數據。但是,基於列來讀取數據,你僅僅需要讀出你想要了解的數據。當然,讀取一條單獨的記錄時,性能上的不同可以忽略,但是許多查詢需要進行全表掃描。當讀取數百萬行數據時,性能的不同就會非常顯著。

Sybase認爲,Sybase IQ的列存儲天然的比普通的ROLAP方法提供更佳的性能,IQ不需要象多數競爭對手或者Sybase Adaptive Server Enterprise(ASE)一樣支持硬件的並行處理。尤其是,Sybase指出,與數據分區相關的問題就是需要支持硬件的並行機制。顯而易見,不論如何進行分區,分區都會帶來很多問題(更不必說額外的維護了),不過,它打開了性能改進的實質性途徑。然而,Sybase進一步闡述道,這僅僅是對基於行的方法所與生俱來的糟糕性能的一種補償機制。

Sybase有很多事實支持它的論斷,但這並不意味着Sybase避免任何形式的數據分區。然而,不同於水平分區,Sybase IQ實施的是垂直分區,也就是說分區是按照列而不是按照行進行的。該方法的優勢之一是分區從來不會變得不均衡,這是由於每個表中的每列都有相同數量的域。這大大降低了管理分區的維護需求,同時消除了數據庫的重新組織,而在分區變得不均衡從而開始影響性能的時候,數據庫重新組織是必需進行的。

最後,需要注意的是,Sybase IQ並沒有避免使用OLAP。對於那些希望在聚合層次下以一個相對預先定義的方式進行查詢的用戶來講,OLAP具有明顯的優勢。基於此,Sybase 支持OLAP功能屬性如排列、百分比、平均。

2.2數據壓縮

傳統的數據庫引擎不能以一種通用的方式進行數據壓縮,主要是由於存在以下三個問題:

1. 按行存儲的數據存儲方式不利於壓縮。這是因爲數據(大多爲二進制數據)在以這種方式存儲時重複並不多。我們發現,按行存儲的數據,最多能有5-10%的壓縮比例;

2. 對於許多2K 和4K 的二進制數據頁來說,爲壓縮和解壓縮而增加的開銷太大;

3. 在OLTP 環境中,大量讀取和更新混雜在一起。每一次更新需要進行壓縮操作,而讀取只需解壓縮操作,大多數的數據壓縮算法在壓縮時比解壓縮時慢4 倍。這一開銷將明顯降低OLTP 數據庫引擎的事務處理效率而使得數據壓縮的代價昂貴到幾乎不能忍受。

在數據倉庫應用中,數據壓縮可以用小得多的代價換取更大好處。其中包括減少對於存儲量的要求;增大數據吞吐量,這相當於減少查詢響應時間。

Sybase IQ 使用了數據壓縮。這是由於數據按列存儲,相鄰接的字段值具有相同的數據類型,其二進制值的範圍通常也要小得多,所以壓縮更容易,壓縮比更高。Sybase IQ 對按列存儲的數據通常能得到大於50%的壓縮。更大的壓縮比例,加上大頁面I/O,使得Sybase IQ在獲得查詢的優良性能的同時,減少了對於存儲空間的需求。

在傳統的數據庫中,爲提高查詢性能所建立的索引佔用的磁盤空間往往需要比數據本身需要的磁盤空間多出3-10倍。而Sybase IQ 存儲數據所佔用的磁盤空間通常只是原數據文件的40%-60%,是傳統數據庫所佔用空間的幾分之一。

Sybase IQ與傳統數據庫在數據壓縮方面的典型對比



智能壓縮技術,與精巧的索引結構和列存儲結合,給了IQ 比其他數據庫引擎高的多的存儲效果。這將獲得更低的存儲成本與更高的性能(因爲系統僅需很少的磁盤I/O讀取或寫入任何給定的數據庫塊)。

2.3索引

Sybase IQ的祕密在於其索引。隨着Sybase 客戶發現了新的分析需求,Sybase可以簡捷地建立新的索引以滿足這些需求。這種方法的奇妙之處在於爲數據倉庫增加新的索引幾乎不會(即使有也是微乎其微)影響數據倉庫的架構或使用倉庫的分析型應用。在實時企業與閉環應用領域,Sybase將索引視爲在TB數量級(將來)甚至PB數量級數據倉庫中獲得更高查詢性能的關鍵。今天,Sybase實際上已使用瞭如下幾種種索引機制:

2.3.1 Low Fast 索引 

這些是低基數索引,它使用一個被稱之爲“代號化”的進程。使用該進程,數據被轉換爲代號,然後存儲這些代號而不是數據。這對於減少冗餘數據的數量尤其有用。例如,在整個英國擁有大量客戶羣的公司,將需要存儲客戶的地址。這將意味着巨大數量的重複的郡的名稱。因此,不是保存大量的“班夫郡”的實例,例如,Sybase將會用一個數字代替每個郡的名稱。因此,由於班夫郡按照拼音排列在英國是第5個郡(排在Aberdeen,Armagh,Avon與Ayrshire之後)因此,它可能就會被設值爲5。如果一個列包含一個數字值,該值自身可以用於代號化的基礎。一旦建立了代號(這是一個自動進行的進程),一個位圖索引將被建立以表示這些代號。代號化典型地應用於列數據存在有限數量的可能取值。這也是爲什麼Sybase稱之爲低基數索引的原因,典型的,它僅用於不同的取值個數在1500以內的域。

2.3.2 Bit-Wise索引

對於高基數的域,那些取值個數超過1500個(如金額值),Sybase使用其專利的被稱之爲Bit-Wise索引.這在你希望在範圍搜索的時候同時進行計算的情況下,尤爲有用,例如,查找銷售價格低於50歐元的貨品數量及總收入。如同位圖的其他變量,該方法的優勢之一就是計數(count)查詢可以直接通過讀取索引獲得答案,而無需讀取數據。

2.3.3 High Group索引

實際上,它是B-樹索引。然而,此處的原則是,用戶僅僅在幾個列有可能作爲一個組來使用的情況下,尤其是高基數與低基數的聯合搜索時,才定義這些索引。比如可能有這樣的例子,按照商店(低基數)查詢產品銷售清單與價格(高基數)。

2.3.4 Fast Projection 索引

該索引類型(缺省的)就是列存儲本身。如果用戶總是打算檢索整個列的數據,則列存儲事實上意味着列可以直接映射到表或查詢中,而無需顯式的定義任何索引。這非常有用,例如在“Where”從句中。

2.3.5 Word 索引

這是一個文本索引。它基於關鍵詞或短語字符串搜索。這種類型的索引,歷史上一直沒有用於數據倉庫中。然而,它有着大量重要的市場,在這些市場上,能夠聯合定量與定性的分析非常重要。例如,在醫療橫業,醫生的診斷通常就是:筆記。爲了獲取信息,例如發病率,因此可能必須訪問這種非結構化的數據。

2.3.6 Compare索引

這個索引技術允許數據列的比較,從效果上講,類似於“if…then…else”表達式。例如,“if支出大於收入,then…”。該類型的索引對於在Web應用中實時比較尤其有用。

2.3.7 Join 索引

正如索引的名稱所示,它是爲消除表連接的需要而設計的。正象大多支持索引的情況,它可能在預先已知的查詢需求下更爲有用。

2.3.8 Time Analytic 索引

這爲基於日期、時間、日期與時間建立索引提供了選項。需要注意的是,對於傳統的關係型數據庫,處理基於時間的查詢尤爲困難。
大量擴展工具用以支持在各種情況下使用這些索引。這包括爲減少硬盤(或內存——位圖可能存在緩衝中)需求的索引壓縮,聯合使用不同類型索引的能力,以及使用布爾操作如AND與OR過濾比特隊列等。這些特性表明,Sybase IQ克服了傳統的位圖的缺陷,即不適合於表連接或數據聚合。Sybase IQ在最近發佈的版本中增加了一個索引顧問(Index Advisor),這一點尤其令人歡欣:這將建議管理員何時應該增加新的索引以及增加那種類型的索引。

三、行列存儲比較

將表放入存儲系統中有兩種方法,而我們絕大部分是採用行存儲的。行存儲法是將各行放入連續的物理位置,這很像傳統的記錄和文件系統。然後由數據庫引擎根據每個查詢提取需要的列。列存儲法是將數據按照列存儲到數據庫中,與行存儲類似;

3.1基於行的儲存

基於行的存儲是將數據組織成多個行,這樣就能在一個操作中找到所有的列。這種做法的缺點是必須每次處理一整行,而不是隻處理自己需要的列。不過,這樣在處理相同實體的兩個或多個列的查詢時能夠取得更快的速度,而且可以提高更新、插入和刪除操作的速度。

基於行的存儲系統可以進行並行處理,並且不需要模仿順序文件系統,儘管有許多產品仍然在這樣做。這種做法的缺點是,一旦確定了這種體系結構,那麼使用的代碼就不僅僅是“老式代碼”,甚至比像“家族的詛咒”那樣的代碼還要難懂。

Teradata是一種非常流行的數據倉庫產品,它使用了散列處理,並且從一開始就具有並行處理機制。最開始的時候它是一種數據庫機,不過當前版本採用的是在標準硬件上建立虛擬機的方式。它從設計上就總是採用並行處理方式。各結點根據實際需要彼此交談,而不是由一箇中央點來控制。萬維網就是採用了這種工作方式,因此對程序員而言,這種模型應該不會太陌生。(結點)數量將數據值儘可能均勻地分散到硬件存儲設備中。如果結點數改變了,那麼系統會重新分佈這些數據。由於採用邏輯地址代替了人們在傳統索引模型中使用的物理地址,因此用戶根本不會看到這些過程。故障結點會對其數據進行重新定位,並將自身從系統中刪除。新結點則會從現有結點將數據傳送到其本地存儲區,刀片服務器上使用了一種建立在內存中的模型。這裏沒有索引;數據都是儘可能多地保存在主存儲器中,並在這裏進行掃描。

3.2基於列的存儲

基於列的訪問存在的缺點是載入速度通常比較慢,因爲源數據在外部來源中是以行或者記錄的形式表示的。這樣做的優點是針對某個列中的值進行簡單查詢的速度非常快,需要的內部存儲資源最少。這表示對某個列中特定值的搜索可以直接進入該列的存儲區,而不需要掃描整行的數據。這樣也使得數據壓縮變得更容易,因爲一個列中的數據通常具有相同的數據類型。這種體系結構在處理數據倉庫使用的海量數據時沒有問題,但不適合需要進行大量以行的方式進行訪問和更新操作的聯機事物處理。就是這種數據庫之一。在由一萬億行組成的測試數據集中,輸入數據共很明顯,這是一種適合數據倉庫的技術。這種技術雖然在壓縮和快速訪問方面有優勢,但也存在插入操作複雜的缺點。

引擎也採用了一種基於列的處理方式,但是它還對值進行標記,以獲得更高的速度和更好的數據壓縮效果。它們使用一種專用的位向量方案,可以在壓縮的狀態下進行搜索。這種技術非常適合檔案處理,但是必須將標記恢復成其原始數據值才能顯示,以及在表達式內使用。不過,在壓縮方面鼓勵將一個數據列分解成更多更詳細的列。

四、列存儲數據查詢中的連接策略選擇方法

4.1 引言

隨着計算機技術的快速發展以及數據庫系統的深入研究和廣泛應用, 人們在期望獲得巨大

數據存儲容量的同時, 對數據的檢索效率, 尤其是即席查詢和決策分析提出了更高的要求。列存儲系統將同一列數據連續存儲, 能避免在查詢中訪問無關列帶來的性能損失, 使查詢操作更有效率, 迅速成爲數據庫領域的研究熱點。不少列存儲系統如C-Store[1]、Sybase[2]、MonetDB[3]等, 都證實了列存儲技術在讀優先系統上的優越性。同時研究也發現, 列存儲查詢雖然可以避免操作無關列, 但還需連接相關列並將其組織成記錄返回給用戶。查詢相關的列越多, 列之間的連接操作就越複雜。面對海量的複雜查詢, 如何使列存儲技術揚長避短, 充分利用其查詢優勢, 成爲了當今列存儲領域的研究重點。查詢優化在數據庫領域一直佔有重要的地位。現有的列存儲系統通過在存儲上做改進來減少查詢中的連接開銷, 如C-Store 的“ 投影(projection)”技術[4−5]將屬於同表的幾列存儲在一起; MonetDB 的“餅乾圖(cracker map)”[6]技術在查詢時建立相關列的映射關係; PAX[7−8]將同一元組的屬性存儲在一個磁盤頁上, 以此來加速同表之間的列連接。可以看出, 列存儲技術雖然在存儲方面已有很多研究成果, 在查詢處理層的優化研究還相當少。這是由於列存儲的處理對象縮小到“列”, 使得候選查詢計劃集合規模增大, 從而增加了查詢優化本身的代價, 影響查詢的性能。然而對連接用單一的處理方式, 也無法達到查詢執行的最優效果。針對上述問題, 本文提出一種連接策略選擇方法, 首先通過簡單規則重寫查詢, 排除代價過大的計劃, 生成候選計劃樹。進而提出動態優化樹算法, 修改候選計劃樹中節點的執行順序, 得到可被轉化爲最優計劃的查詢樹。根據列存儲的特點, 查詢樹中連接節點的連接策略可歸納爲兩種:串行連接與並行連接。在此基礎上構建代價估計模型進行代價估計和策略選擇, 不僅有效減少了代價估計的開銷, 也增加了列存儲查詢處理的靈活性。經分析, 本文提出的連接策略選擇方法能有效優化查詢, 使得查詢效率顯著提高。

4.2 相關工作

列存儲的概念可以追溯到20 世紀70 年代,1976 年加拿大統計局開發實現了列存儲數據庫

管理系統RAPID[9], 並在80 年代廣泛應用。隨着企業對分析型查詢需求的快速增長, 對列存儲的研究在近十年得到了提升。早期的列存儲模型有分解存儲模型(DSM)[10]、PAX 等。新的列存儲系統包括MonetDB/X100[11]、C-Store 等。研究表明,列存儲數據庫系統在分析型業務中的性能比行存儲數據庫系統性能超出多個數量級[5]。查詢優化在數據庫領域佔有重要地位。目前較爲成熟的優化方法有兩類:基於規則的優化方法(rule based optimization, RBO)以及基於代價的優化方法(cost based optimization, CBO)[12−14]。基於規則的優化方法根據指定的規則或定義路徑的優先級對邏輯計劃進行優化。基於代價的優化方法通過統計信息和存取路徑評估所有候選計劃的代價, 選擇代價最小的一個。通常優化器選擇結合這兩種方法來進行優化[14]。然而, 在列存儲系統中的優化卻相當少, 目前的列存儲查詢處理, 都將重點放在物理存儲的改變上, 沒有統一的規則或代價的權衡。C-Store 是開源列存儲系統, 它將每列單獨存儲, 多列保存在一個投影(projection)中, 按照其中一列排序[1,4−5]。因此C-Store 查詢經常基於一個投影, 或者含有公共排序列的不同投影, 以此減少列的連接代價。連接操作首先根據對排序列的篩選, 得到position 列表並用它過濾其他列。因此需要通過索引檢索position 的第一個值來定位其他列的起始查找位置[4]。position 是基於排序列的, 若執行的謂詞列在任何投影中都沒有排序,則需對其進行全列掃描, 這樣代價很大。MonetDB 以(key, value)形式存儲數據, 利用“餅乾圖(cracker map)”來連接列。在多選擇列之間, 選擇某一列作爲基列(左列), 跟其他相關列兩兩綁定在一起。根據左列的篩選條件進行分區, 並建立該分區的索引, 重新存儲爲M(crackermap)。由於基列一樣, 使用位圖向量之間的位與來連接列[6]。此方法在第一次查詢的時候需要消耗大量的內存, 對列進行範圍的劃分以及索引的建立。在以後的查詢中, 如果基於該列的謂詞發生變化, 需重新劃分範圍並修改索引。該方法內存消耗巨大, 僅適用於內存數據庫MonetDB , 卻無法在列存儲系統上通用。上述兩個系統, C-Store 的查詢執行器相當完善, 但是查詢優化器卻未實現[4]。MonetDB 的查詢處理中, 執行計劃並不通過代價模型評估, 僅是通過啓發式規則來重寫計劃[15]。可見現有的列存儲系統連接策略單一且侷限, 在查詢優化方向的研究非常少。本文結合簡單規則和動態Huffman算法, 建立基於代價的連接策略選擇模型, 針對不同情況處理列之間的連接。

4.3 定義

定義 1 (空間) 列存儲數據的查詢處理對象爲列, 屬於一張表的列屬於同一個空間。定義 2 (rowid) 爲了重組一行數據, 每一列都附加一個僞列rowid, 形如, 如圖

1.  每一列在rowid 上都存在B 樹索引。

定義 3 (連接) 同空間內由and 連接的兩個操作、兩個列的比較操作稱爲同空間列的連接; 不同空間兩列間的操作稱爲不同空間列的連接。定義 4 (串行連接) 一個連接操作的對象有兩個孩子操作, 用一個操作的結果通過連接條件去過濾另一個操作的方法稱爲串行連接, 如圖2。定義 5 (並行連接) 先分別執行兩個相關操作,再通過連接條件得到結果的方法稱爲並行連接,如圖3。

定義 6 (驅動列) 連接操作中, 兩個處理對象中較少行數的列爲驅動列。它可以是原始數據,

李靜 等:列存儲數據查詢中的連接策略選擇方法 853也可以是中間結果中的列。定義 7 (被探測列) 當從驅動列得到了一項數據以後, 在該探測列中查找符合條件的數據。

對於 SQL:select m from A, B where A.m=B.n其中m 爲驅動列, 則連接策略如圖2 和圖3。

4.4 連接策略選擇方法

本文重點研究如下形式的查詢:select A from T where Λ(P1,P2 ,...,Pm) (1)

T 是查詢引用的關係集合; A 是引用關係T 的屬性集; (P1,P2 ,...,Pm)是由and 連接的謂詞。對於列存儲而言, 該查詢可轉化爲如下形式:

Ci 是查詢相關的列, 如果Ck 上不存在選擇謂詞,設σ(Ck)爲true。Fij 是連接條件, 如果Ci、Cj 上不存在連接謂詞, 設Fij 爲true。對於n 個節點的查詢樹來說, 列之間連接方法有種。基於代價的優化連接策略就是從中選擇一個I/O 最小的計劃, 然而數據按列存儲後, n 往往很大, 這使得從中選擇一個理想計劃十分困難, 因此需要首先根據簡單的規則削減計劃的選擇範圍。

4.4.1 簡單下推規則

根據啓發式原理:由於關係越小, 所需讀寫的I/O 也就越少, 因此中間結果之和較小的計劃

很可能是較好的計劃[12]。本文根據關係代數表達式的下推規則來執行不同空間的謂詞下推; 並使用列的級聯規則合併同列選擇謂詞[12]; 最後處理列間的連接謂詞。通過以上規則得出式(2)中where 子句的形式:

定義選擇空間 T, 連接空間J:

查詢計劃如圖4, 用於連接的左深樹能和連接算法很好地交互, 有利於形成有效的計劃[12]。

4.4.2 動態優化樹

對左深連接樹而言, 應該選用估計數值較小的節點作爲左變元[12]。本文結合動態Huffman

樹[16]思想提出動態優化樹算法, 改進查詢執行順序, 保證執行該樹的代價儘可能最小, 如圖5。(1) 利用動態Huffman 樹原理修改空間之間的連接順序。設 Tout 爲每個空間根節點的輸出元組數, 查詢計劃中的選擇空間根節點Ti∈{T1,T2,…,Tn}的權值爲Tiout。若存在某空間與多空間連接, 將該空間作爲最左空間, 根據動態Huffman 樹原理修改該空間與其他空間的連接順序。若不存在這樣的空間, 則修改所有空間的連接順序。(2) 利用動態Huffman 樹原理, 修改空間內的連接順序。

優先處理選擇性較好的謂詞可以儘早減少需處理的元組數目, 從而避免I/O 的浪費[12]。設

C.ff 是C 列上滿足篩選條件的選擇率[17], 選擇率越小, 選擇性越好。若T 空間有n 個葉子節點, 設其權值爲:C1.ff,C2.ff, …, Cn.ff. 。T 內Ci、Cj 列的連接結果權值爲Ci.ff×Cj.ff, 因此動態Huffman樹算法相當於從左至右結合最小ff 的節點。由於處理最左節點的I/O 過大會影響整體計劃的I/O,優先處理帶有索引的節點能夠有效減少整體I/O。如圖 4 所示, 當查找到C3 列的選擇節點f3 是擁有索引的最小ff 節點, 且F2 僅是rowid 相等的連接條件時, 新建N_node 節點, 並通過1~4 步修改樹的執行順序, 刪除虛線節點。對於每個連接節點, 其連接方式可歸納爲兩種:

串行連接和並行連接。若對每個節點都採用並行連接, 需考慮讀取每列數據的I/O, 開銷相當大。若都採用串行連接, 需考慮重複查找索引塊和數據塊帶來的額外開銷, 以及沒有索引的情況下帶來的巨大I/O 浪費。因此, 有必要定義代價估計模型進行策略選擇。

4.4.3 基於列的代價估計模型

查詢計劃的連接節點有兩類:T 空間的中間節點和J 空間的葉子節點。針對這些節點的特點,本文提出一種代價估計模型:M={I, O, A}, 爲每個節點決定連接策略。其中 I 是M 模型的輸入信息, 是查詢樹節點的統計信息。它包括:

T 空間中間節點的統計信息node_info={Tout (A),B_info A∈T,B∈T} (7)Tout(A)是驅動列A 的篩選結果行數[17]; B_info 是被探測列的統計信息。

其中, FF(B)爲B 列上滿足條件的選擇率[17]; B(B)爲容納一列B的數據塊個數; T(B)爲B的行數; V(B)爲B 列的基數, 即B 列上不同值的個數; Htr(B)爲B 列上rowid 索引的層數; Htv(B)爲B 列上value索引的層數。J 空間的葉子節點的相關統計信息

node_info={J_info,T1_info, T2_info,Tmid_info} (9)

J_info={A_info, B_info A∈T1, B∈T2} (10)

{ } T1_info= T1out ,Columnlist (11)

{ } T2_info= T2out ,Columnlist (12)

{ , } out Tmid_info= T Columnlist (13)

其中J_info 是連接節點的信息; T1_info 是J 的左孩子所在空間的根節點信息, 它可以是T 空間的根節點, 也可以是J 空間的根節點; T2_info 是J的右孩子所在空間的根節點信息; Tmid_info 是先前節點處理的T1與T2的連接結果, 由於最左葉子節點還未處理連接, 因此該項統計信息爲空;Columnlist 是相應空間內處理過的列的列表。O 是M 模型的輸出集合, 它爲每個連接節點選擇代價最小的連接策略;A 是M 模型的算法, 分別針對T 空間的中間

節點和J 空間的葉子節點給出相應的策略選擇。其中涉及的量值計算如下:

列存儲系統的每一列數據的B樹索引都是聚

簇索引。當A 爲驅動列時, B 列與A 列的連接在B上所產生的磁盤I/O 爲:

(1) 串行連接

① 根據 B 的索引:

對於驅動列A 中的每一條數據, 都約有B(B)/V(B)個符合條件的數據塊。

② 根據 B 的rowid:

連接代價爲查找索引塊與數據塊之和, 其中數據塊可估計爲:驅動列篩選的結果最稀疏和最

密集情況的折中。

(2) 並行連接

① 全列掃描:

FS(B)= B(B) (16)

② 索引掃描:

IS(B)=Htv(B)+B(B)× FF(B)

使用後序遍歷查詢樹, 用M 模型算法A:

Cost_Model (node_info)爲節點選擇連接策略。

圖 6 算法中2~5 行代碼處理T 空間的中間節點, 爲每個連接節點評估串行連接和並行連接的 I/O, 選取產生較小I/O 的連接方式。算法的 6~23 行處理J 空間的最左葉子節點:

(1) T1 處理的結果包含A 列, 可確定J 與T1空間的串行連接方式。T2 包含B 列時, 可確定A、B 並行, J 與T2 串行。T2 不包含B 列時, 根據代價的權衡來決定連接方式。(2) T1 處理的結果不包含A 列, 可根據代價估計A 列與T1 列的串並行I/O, 選擇產生較小I/O的策略。接下來處理同(1)。算法的 24~29 行鍼對J 空間的右葉子節點:(1) T1、T2 篩選結果不包括A、B 列, 且節點本身獨立執行連接的代價不大於過濾其兄弟節點的代價, 選擇並行連接。

(2) 其他情況下, 用右節點直接過濾其左兄弟節點的結果。

4.4.4 優化算法及理論分析

至此, 本文給出列存儲數據查詢中的連接策略選擇方法的總算法:Opt_Plan (tree), 如圖7。

該算法對前文如(2)形式的SQL語句生成的語法樹進行優化處理, 得到優化的查詢計劃。列存儲數據查詢可生成大量的候選查詢計劃, 中間關係的估計能夠幫助選擇較優的邏輯計劃。本文用式(18)形式的SQL語句, 分析Opt_Plan算法。相關統計信息如表1 所示。

select , , , from ,

where and

and and

A.a A.b B.a B.c A B

A.b= 9 B.c= 8

A.c=6 A.a= B.a

同空間內 rowid 唯一, 每一個選擇條件都能減少先前操作所產生的中間結果。執行A.b=9 and B.c=8 意味着兩個空間的笛卡爾積操作, 中間元組約爲7 500; 執行A.b=9 and A.c=6 產生的中間元組約爲2。可見優先執行同空間內的選擇, 能儘早減少需要處理的元組。因此優化的首要步驟是利用簡單下推規則,排除代價過大的計劃。驅動列的元組數是決定連接操作I/O 的主要因素。單獨考慮A.a=B.a 節點, 將B.a 作爲驅動列,串行連接需要約12 000 次I/O。將A.a 作爲驅動列, 串行連接需要約7 000 次I/O。可見利用動態優化樹算法修改執行順序, 確定左變元爲驅動列是非常重要的。簡單規則和動態優化樹算法都能有效地縮小中間結果之和, 具有最小中間結果之和的計劃可能是較好的計劃[12]。當涉及到具體執行時, 較小I/O 的計劃被認爲是較優計劃, 因此對連接策略的選擇非常重要。對優化過的式(18)產生的計劃僅使用串行連接策略, 需要約245 次I/O(公式(19)); 僅使用並行連接策略, 需要約576 次I/O(公式(20)); 而M 模型評估的策略, 需要約95 次I/O(公式(21))。由於B.a 列不存在索引, 串行連接和並行連接都需要全列掃描B.a, I/O 開銷較大。

可見 M 模型能夠評估選擇最優的連接策略,本算法能夠有效地優化查詢計劃。不僅如此, 本文算法具有較好的可擴展性, 算法思想能在開源列存儲系統上通用。以 C-Store 爲例, C-Store 僅對排序列建立索引, 或者對所有列建立position 索引[4]。對於式(18)語句的A 表篩選條件來說, 若存在projection 包含A.b、A.c、A.a, 且根據A.c 排序, 則C-Store 系統上的計劃爲:全列掃描A.b 列, 得到長度約爲100的position; 定位A.c 列的第一個position, 抽取A.c列相應position 上符合條件的值, 得到長度約爲2的position, 最後得到A.a。優化後的計劃爲:索引掃描A.c, 忽略對索引塊的訪問, 可能只需要一個數據塊的I/O, 得到長度爲20 的position, 過濾A.b 列, 得到長度爲2 的position, 最後得到A.a。顯然, 經過優化的計劃能以更小的I/O 得到較優的查詢計劃, 可見本文提出的優化算法思想可通用於列存儲系統。

5 總結與展望

上述提出的方法根據簡單規則過濾了代價過大的計劃, 進而提出動態生成樹算法, 根據動

態Huffman 樹原理對候選查詢計劃樹中的查詢執行順序進行修改並最終得到可生成較優計劃的候選樹。經分析, 該步驟能減少列連接過程中的I/O 開銷。同時, 提出了基於代價的優化連接策略選擇方法, 它針對數據按列存儲後並行連接和串行連接兩種策略進行代價估計和策略的選擇, 充分利用了串行連接和並行連接各自的優勢, 爲列存儲的查詢優化提出了新的策略。經分析, 本模型能以較小的時空開銷完成查詢計劃的優化。今後的工作重心將轉向對並行連接策略的進一步研究, 對適用於列存儲的哈希連接和排序合併連接等策略進行分析優化, 使列存儲查詢計劃得到進一步的優化處理。

五、列存儲數據庫的安裝

MonetDB是一個開源的高性能列存儲數據庫系統,比基於行存儲的MySQL性能最多可提高10倍 , 參見 MonetDB的TPC-H 性能測試。 MonetDB目前仍然是一個學術機構的開源項目,差不多每6個月出一個Release,由於Bug衆多並不推薦在生產環境中使用。

關於列存儲數據庫(Column-oriented DBMS) 近年來,從商業產品(Sybase IQ)到開源的BigTable類項目(HyperTable, Hbase, Cassandra等),列存儲數據庫在OLAP應用中的地位越來越突出。

安裝步驟(CentOS 5.2 x86_64),安裝過程同時編譯了MonetDB的Java和PHP客戶端庫:

5.1預先安裝JDK, ANT和PHP

#wget http://apache.mirror.phpchina.com/ant/binaries/apache-ant-1.7.1-bin.tar.gz

將它們加入執行路徑,例如/etc/profile中加入

export JAVA_HOME=/usr/local/jdk1.6.0_06

export ANT_HOME=/usr/local/apache-ant-1.7.0

export PATH=$PATH:$JAVA_HOME/bin:$ANT_HOME/bin:/usr/local/php-fcgi/bin

配置完後,重新登錄,確認相關可執行文件的路徑:

# java -version

java version "1.6.0_06"

Java(TM) SE Runtime Environment (build 1.6.0_06-b02)

Java HotSpot(TM) 64-Bit Server VM (build 10.0-b22, mixed mode)

# javac -version

javac 1.6.0_06

# php-config

Usage: /usr/local/php-fcgi/bin/php-config [OPTION]

Options:

--prefix            [/usr/local/php-fcgi]

--includes          [-I/usr/local/php-fcgi/include/php -I/usr/local/php-fcgi/include/php/main -I/usr/local/php-fcgi/include/php/TSRM -I/usr/local/php-fcgi/include/php/Zend -I/usr/local/php-fcgi/include/php/ext -I/usr/local/php-fcgi/include/php/ext/date/lib]

--ldflags           [ -L/usr/kerberos/lib64]

--libs              [-lcrypt   -lcrypt -lrt -lldap -llber -lpng -lz -ljpeg -lcurl -lz -lresolv -lm -ldl -lnsl -lxml2 -lz -lm -lssl -lcrypto -ldl -lz -lcurl -lgssapi_krb5 -lkrb5 -lk5crypto -lcom_err -lresolv -ldl -lidn -lssl -lcrypto -lz -lxml2 -lz -lm -lxml2 -lz -lm -lxml2 -lz -lm -lcrypt -lxml2 -lz -lm -lxml2 -lz -lm -lxml2 -lz -lm -lxml2 -lz -lm -lcrypt ]

--extension-dir     [/usr/local/php-fcgi/lib/php/extensions/no-debug-non-zts-20060613]

--include-dir       [/usr/local/php-fcgi/include/php]

--php-binary        [/usr/local/php-fcgi/bin/php]

--php-sapis         [cli cgi]

--configure-options [--prefix=/usr/local/php-fcgi --with-config-file-path=/usr/local/php-fcgi/etc --enable-sockets --enable-pcntl --enable-mbstring --with-iconv --with-gd --with-curl --with-zlib --with-jpeg-dir --with-ttf --with-ldap --with-gettext --enable-soap --with-xmlrpc --with-openssl --enable-fastcgi --enable-discard-path --enable-force-cgi-redirect]

--version           [5.2.6]

--vernum            [50206]

5.2 從MonetDB主頁下載 MonetDB-Jun2008-SuperBall.tar.bz2 (實際上從SourceForge)

#tar xvjf MonetDB-Jun2008-SuperBall.tar.bz2

#cd MonetDB-Jun2008-SuperBall

執行

#./monetdb-install.sh --prefix=/opt/MonetDB --enable-sql --enable-optimize

則安裝編譯MonetDB到/opt/MonetDB下。

PHP擴展等會自動編譯,生成於 /opt/MonetDB/lib/php/extensions/下。

5.3 啓動MonetDB服務器的方法是

#/opt/MonetDB/bin/mserver5 --dbinit="include sql;"

5.4 執行MonetDB 的SQL查詢客戶端

#/opt/MonetDB/bin/mclient -lsql  --time







  以前不是特別明白列式存儲和行式存儲到底有什麼區別,對於突然蹦出來的BigTable、HBase、Cassandra這些NoSQL數據庫憑什麼比MySQL集羣,Oracle在分析存儲上的強大?思來可以這樣說說。

     A. 存儲

     傳統RDBMS以行單位做數據存儲(字段爲空則賦值爲‘NULL'),列式存儲數據庫以列爲單位做數據存儲。如下:

對於列式存儲來說,一行數據包含一個列或者多個列,每個列一單獨一個cell來存儲數據。而行式存儲,則是把一行數據作爲一個整體來存儲。

     另外一個不得不提的是,列式存儲天生就是適合壓縮,因爲同一列裏面的數據類型基本是相同,筆者在之前使用普通的gzip壓縮,200MB的字符串數據,經過壓縮之後只剩下8MB。當然gzip並不屬於增量壓縮,我們可以選擇增量壓縮的方式來滿足一些數據的隨機查找。

      B.  查詢

      從查詢來說,行式存儲比較適合隨機查詢,並且RDBMS大多提供二級索引,在整行數據的讀取上,要優於列式存儲。但是,行式存儲不適合掃描,這意味着要查詢一個範圍的數據,行式存儲需要掃描整個表(因爲這些記錄不是順序存儲的),在索引建立不當的情況下,查詢大表(千萬數據)簡直是噩夢。

      列式存儲,最早接觸的可能不是所謂的BigTable,大多數以前的數據倉庫都是採用列式存儲。列式存儲一般行KEY,列KEY(不是列值)都是順序存儲,比如我要查詢一個時間段裏面,某個值的出現頻率,我可能只需要涉及到兩個列。

在分析上,列式存儲要優於行式存儲,列式存儲的數據庫一般情況下也強烈建議用戶按需查找,而不是整行數據去獲取。列式存儲在這方面減少了IO的壓力

      C. 結語

     沒有說誰比誰更優,在正真實戰的情況,考慮實際情況。比如傳統的RDBMS提供ACID原子操作和事務,在大多數列式存儲數據庫上是不具備的,大多數列式存儲數據庫對分佈式支持友好。

      需要知道的是,列式存儲以及行式存儲在查詢和存儲上的本質,在技術選型上多點籌碼。

       


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章