列存(Column-Oriented)數(shù)據(jù)庫學習筆記:內(nèi)存數(shù)據(jù)壓縮

大數(shù)據(jù)技術已經(jīng)從幾年前的熱門概念落地為實用技術颜懊,為互聯(lián)網(wǎng)貢獻了重要力量。

隨著移動應用發(fā)展吞杭,數(shù)據(jù)緊密包裹用戶,
數(shù)據(jù)分析(OLAP)要求日益提高变丧,數(shù)據(jù)量芽狗、查詢延時都面臨極大挑戰(zhàn)。

這種情況下痒蓬,列存童擎、行列混存數(shù)據(jù)庫技術,在冷門多年后又重新獲得了極大關注攻晒。

我們一起來看個案例顾复,Mark Litwintschik使用十億條的士載客記錄,
在不同的軟硬件平臺上測試了的分析查詢性能:
http://tech.marksblogg.com/benchmarks.html

可以看到炎辨,除了MapD(GPU數(shù)據(jù)分析平臺)遙遙領跑之外捕透,
(跑在8路泰坦、半T內(nèi)存這種怪獸硬件上)
列存數(shù)據(jù)庫ClickHouse僅憑借單機普通硬件碴萧,
就達到了Spark這樣專門的大數(shù)據(jù)平臺的百倍性能乙嘀,非常驚人。

基于此破喻,近期考慮對OLAP架構虎谢,尤其是列存數(shù)據(jù)庫做深入的學習探索,
相關筆記就在此記錄曹质。

一些資料

VLDB婴噩、SIGMOD擎场、ICDE:

數(shù)據(jù)庫技術最重要的期刊會議。

Vertica:

HP的商業(yè)列存數(shù)據(jù)庫几莽,以C-Store為原型迅办,在AWS上有托管分析服務售賣。
在最開始的測試案例中章蚣,可以看到Vertica雖然沒有ClickHouse快站欺,
但也以單機跑出了接近10節(jié)點Spark集群的成績。

Daniel.J.Abadi:

列存數(shù)據(jù)庫C-Store的開發(fā)者纤垂,在各大期刊上發(fā)表過多篇關于列存數(shù)據(jù)庫的Paper矾策。
其09年的“Query Execution in Column-Oriented Database Systems”骗卜,
對列存數(shù)據(jù)庫的各方面都做了詳細敘述愧旦。

何為列存數(shù)據(jù)庫?

我們熟悉的Mysql等數(shù)據(jù)庫析既,是按行存放數(shù)據(jù)的:

+--------+-----+
| name   | age |
+--------+-----+
| 孫麗華  |  21 |
| 王永恒  |  23 |
| 張偉朋  |  21 |
+--------+-----+```

這樣的數(shù)據(jù)存儲方式吼鱼,每次增加數(shù)據(jù)可以在末尾增加一行就行蓬豁。
(實際比此復雜)

列存數(shù)據(jù)庫則把行列倒轉,并把不同列分開存放:

+--------+--------+--------+--------+
| name | 孫麗華 | 王永恒 | 張偉朋 |
+--------+--------+--------+--------+
+--------+--------+--------+--------+
| age | 21 | 23 | 21 |
+--------+--------+--------+--------+


列存數(shù)據(jù)庫在增加數(shù)據(jù)時IO不連續(xù)蛉抓,需要在每個列后面追加數(shù)據(jù)庆尘,寫性能不佳,
因此一直沒有成為主流的業(yè)務系統(tǒng)(OLTP)的首選數(shù)據(jù)庫巷送。

如前所述驶忌,大數(shù)據(jù)量下的OLAP是個挑戰(zhàn),它的用況特征我們可以列舉一下:
    - 數(shù)據(jù)是批量導入的笑跛,導入后不修改
    - 絕大多數(shù)是讀操作
    - 每個表有很多列付魔,分析操作經(jīng)常只涉及小部分列

可以看出,OLAP用況很吻合列存數(shù)據(jù)庫飞蹂,
既避開了列存的細粒度寫性能的劣勢几苍,
又發(fā)揮了讀少數(shù)列時節(jié)省IO、不需要讀無用列的優(yōu)點陈哑。

列存將相似數(shù)據(jù)緊密排列妻坝,對內(nèi)存、CPU和磁盤都很友好惊窖,
這篇筆記的主要關注在(單機下的)列存數(shù)據(jù)在內(nèi)存和CPU的處理刽宪,
磁盤上的存儲布局也是一個較大的話題,會放到另一篇筆記界酒。


# 列存數(shù)據(jù)的SIMD優(yōu)化

數(shù)據(jù)的運算在CPU上進行圣拄,
CPU的數(shù)據(jù)吞吐量(Throughput)越大,計算就越快毁欣,數(shù)據(jù)分析也就越快庇谆。

CPU性能 = 每周期執(zhí)行指令數(shù)(IPC岳掐,Instructions Per Cycle)× 頻率
硬件本身決定了IPC上限和頻率。

90年代饭耳,Intel等CPU廠商設計了MMX串述、SSE等單指令多數(shù)據(jù)(SIMD)的指令集,
顧名思義哥攘,就是一條指令處理一批數(shù)據(jù)剖煌,提高計算能力。
時至如今逝淹,SIMD仍是最重要的優(yōu)化手段之一。

對于列式存放的數(shù)據(jù)桶唐,在內(nèi)存里緊密排列栅葡、大小相同,
可以很容易地進行SIMD處理尤泽,批量地加載進CPU欣簇,由一次CPU指令處理完。
這就在不變的硬件條件下坯约,成倍地提高了數(shù)據(jù)吞吐量熊咽。

緊密數(shù)組的遍歷處理,對CPU流水線很友好闹丐,
即使在代碼中沒有特殊作SIMD處理横殴,
編譯器也可以使用loop-pipelining等手段進行優(yōu)化,達到更高效率卿拴。


# 列存數(shù)據(jù)壓縮

在CPU數(shù)據(jù)吞吐量固定的情況下衫仑,數(shù)據(jù)壓縮是提升處理速度有效途徑。

常見的壓縮算法如lz77堕花、lz78家族文狱,對數(shù)據(jù)都做了變形處理,
然后在一個較大(k級)的數(shù)據(jù)窗口中尋找相同的數(shù)據(jù)達成壓縮缘挽。

這類壓縮的結果與原始數(shù)據(jù)相去甚遠瞄崇,進行計算之前需要解壓,
我們稱為通用壓縮或者重型壓縮(Generic Compression/Heavy Compression)
這類壓縮的特點是壓縮率高壕曼,壓縮慢苏研,解壓較快,消耗CPU資源較多窝稿。

列存數(shù)據(jù)由于相鄰數(shù)據(jù)相似度非常高楣富,
可以進行針對數(shù)據(jù)特征的輕量壓縮(Lightweight Compression)
并可以直接對壓縮處理進行計算。

輕量壓縮消耗CPU資源極少伴榔,壓縮比普遍在1/3-1/4纹蝴,
理想情況下庄萎,可以提升對應倍數(shù)的吞吐量。


# 輕量壓縮的算法框架

###### 輕量壓縮算法有很多種塘安,常用的有:
    - 前綴壓縮(Prefix Suppression):
    - 位向量編碼(Bit-Vector Encoding)
    - 字典編碼(Dictionary Ecoding)
    - 參照系編碼(FOR糠涛,F(xiàn)rame of Reference Encoding)
    - 差異編碼(Defferential Encoding/PFOR-DELTA)

###### 下面簡單列一下各個算法的要點。

- 前綴壓縮(Prefix Suppression):
  消除相同前綴兼犯,常用狀況:列中大部分都是小值忍捡,但最大值較大

- 位向量編碼(Bit-Vector Encoding):
  列中大多數(shù)值都相同,比如性別切黔,以1個bit來表達砸脊。
  編碼后數(shù)據(jù)還可以再次壓縮。

- 字典編碼(Dictionary Ecoding):
  適用于唯一值(Distinct Values)數(shù)量較少的情況纬霞,例如季度凌埂、國家
  預提取預存字典的KV對,數(shù)據(jù)里存K诗芜。
  壓縮后數(shù)據(jù)長度為log 2(|D|) bits瞳抓,D是唯一值數(shù)量

- 參照系編碼(FOR,F(xiàn)rame of Reference Encoding):
  選擇參照值伏恐,每個數(shù)據(jù)只存與參照值的差值孩哑,
  壓縮后每值占log 2(max ? min + 1) bits
  變種FOR: 選擇可以小于0的參照值,使的每個值都為正數(shù)翠桦。

- 差異編碼(Defferential Encoding/PFOR-DELTA):
  和參照系編碼類似横蜒,使用前一個值作為參照值
  對于遞增遞減的數(shù)據(jù)性能良好。
  例如時間戳秤掌、遞增ID愁铺、有序數(shù)組

- 行程編碼(Run-Length Encoding,RLE):
  將一串連續(xù)的相同數(shù)據(jù)轉化為特定的格式
  例如:aaabbc闻鉴,表示為:3個a茵乱,2個b,1個c孟岛,壓縮數(shù)據(jù)3a2b1c
  RLE是很基礎的壓縮方式瓶竭,通用壓縮算法中也很多它的影子,
  但通用壓縮中經(jīng)常結合多種算法渠羞,例如使用BWT可逆變換提高重復率斤贰。
  作為原始的、沒有經(jīng)過數(shù)據(jù)變形的RLE次询,更利于在壓縮數(shù)據(jù)上進行計算荧恍。

###### 這些算法都可以在同一個算法框架下工作:
    - 找到數(shù)據(jù)特征,大部分數(shù)據(jù)都應該符合該特征
    - 對數(shù)據(jù)逐個進行編碼,達成壓縮送巡,不同的壓縮算法采用不同的編碼方式
    - 如果碰到不符合特征的數(shù)據(jù)摹菠,按異常值(Exception Values)處理
    - 異常值的處理方式:編碼為“跳出碼(Escape Code)+ 原始數(shù)據(jù)”
    - 跳出碼與正常值長度相等,其值為正常值不可能的值骗爆。所對應的原始數(shù)據(jù)可以另外存放

用偽碼來表示編碼過程:
```c
for i = j = 0; i < n; i++:
  if in[i] < MAXCODE:
    out[i] = CODE(in[i])
  else:
    out[i] = MAXCODE
    exception[j++]) = out[i]```

解碼為逆過程:
```c
for i = j = 0; i < n; i++:
  if in[i] < MAXCODE:
    out[i] = DECODE(in[i])
  else:
    out[i] = exception[j++])```

有兩個事情值得注意:
1次氨,exception的數(shù)據(jù)比例對性能的影響。
2摘投,if-else分支引發(fā)的指令預測失敗煮寡,IPC(Instructions Per Cycle)下降的問題。

Marcin Zukowski在引文中測試了不同壓縮算法犀呼、不同exception比例下的性能幸撕,
并且嘗試使用兩輪循環(huán)避免if-else分支,有興趣可以看看圆凰。

在實踐中杈帐,不同的數(shù)據(jù)列可以根據(jù)特征和需求來決定壓縮策略,
工程師們提出過不少策略专钉,以下是其中一種決策樹:

該列有排序查詢的需求嗎
Y => 平均重復行程(Average Run-Length)> 2嗎
Y => RLE壓縮
N => 差異編碼
N => 唯一值(Distinct Values)數(shù)量 < 50000嗎
Y => 該列經(jīng)常出現(xiàn)在選擇謂詞(即SQL where子語句)中嗎
Y => 位向量編碼
N => 字典編碼
N => 是有局部性(某范圍值較多)的數(shù)字類型嗎
Y => 參照系編碼
N => 不壓縮或者重型壓縮

在實際開發(fā)中,列數(shù)據(jù)一般被分成多個等大Block累铅,
每個Block可以有自己的元數(shù)據(jù)(例如參照值)跃须,也可以引用別的Block的,
甚至可以再次對特征采樣娃兽,選擇不同的壓縮策略菇民。
可見落地過程中的優(yōu)化空間還是很大的,需要結合實際數(shù)據(jù)測量效率投储。


# 對于壓縮數(shù)據(jù)的計算

輕量壓縮的結果與原始數(shù)據(jù)成一一映射的關系第练,
幾乎所有的算術運算都可以直接在壓縮結果上計算。

舉例玛荞,原始數(shù)據(jù)[102, 101, 104]娇掏,使用FOR編碼,以100為參考值編碼為[2, 1, 4]勋眯,
那么(if > 101)的運算就被改寫為(if > 1)婴梧,可以直接在編碼后數(shù)據(jù)上計算。

即使我們不使用改寫計算的方法來處理數(shù)據(jù)客蹋,
而是使用解壓后計算的常規(guī)方式塞蹭,上述的輕量壓縮仍舊可以帶來巨大好處:

我們知道,RAM對比CPU來說是很慢的讶坯。
下表是數(shù)據(jù)在各個設備上存取數(shù)據(jù)的大概耗時比例番电,單位是時鐘周期Cycle:

L1-CACHE 4
L2-CACHE 11
L3-CACHE 18
RAM 160```

計算過程:
- 壓縮數(shù)據(jù)從RAM進入CACHE
- 送入CPU解壓
- 進行業(yè)務運算
- 再壓縮,結果留在CACHE
- 寫回RAM

可見最耗時的兩次IO:RAM-CACHE/CACHE-RAM辆琅,傳輸?shù)亩际菈嚎s數(shù)據(jù)漱办,
該技術被稱為RAM-CPU CACHE Compression这刷,
有效減少了RAM-CPU交換,增加了吞吐量洼冻。

以上涉及的都是列數(shù)據(jù)的通用的計算優(yōu)化崭歧,
對于其在關系代數(shù)運算(查詢)中的優(yōu)化,
也是一個較大的話題撞牢,需要另外的篇幅來敘述率碾。

主要參考資料

以下論文可以在各大學術庫下載

- “Query Execution in Column-Oriented Database Systems” Daniel Abadi SIGMOD’09
- “Super-Scalar RAM-CPU Cache Compression” Zukowski, Heman, Nes, Boncz, ICDE’06
- “Weaving relations for cache performance” Ailamaki, DeWitt, Hill, and Skounakis. VLDB’01
- “Integrating Compression and Execution in Column-Oriented Database Systems” Abadi, SIGMOD’06
- “MonetDB/X100: Hyper-Pipelining Query Execution” Peter Boncz, CIDR’05
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市屋彪,隨后出現(xiàn)的幾起案子所宰,更是在濱河造成了極大的恐慌,老刑警劉巖畜挥,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件仔粥,死亡現(xiàn)場離奇詭異,居然都是意外死亡蟹但,警方通過查閱死者的電腦和手機躯泰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來华糖,“玉大人麦向,你說我怎么就攤上這事】筒妫” “怎么了诵竭?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長兼搏。 經(jīng)常有香客問我卵慰,道長,這世上最難降的妖魔是什么佛呻? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任裳朋,我火速辦了婚禮,結果婚禮上件相,老公的妹妹穿的比我還像新娘再扭。我一直安慰自己,他們只是感情好夜矗,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布泛范。 她就那樣靜靜地躺著,像睡著了一般紊撕。 火紅的嫁衣襯著肌膚如雪罢荡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音区赵,去河邊找鬼惭缰。 笑死,一個胖子當著我的面吹牛笼才,可吹牛的內(nèi)容都是我干的漱受。 我是一名探鬼主播,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼骡送,長吁一口氣:“原來是場噩夢啊……” “哼昂羡!你這毒婦竟也來了?” 一聲冷哼從身側響起摔踱,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤虐先,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后派敷,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛹批,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年篮愉,在試婚紗的時候發(fā)現(xiàn)自己被綠了腐芍。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡试躏,死狀恐怖甸赃,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情冗酿,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布络断,位于F島的核電站裁替,受9級特大地震影響,放射性物質發(fā)生泄漏貌笨。R本人自食惡果不足惜弱判,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锥惋。 院中可真熱鬧昌腰,春花似錦、人聲如沸膀跌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽捅伤。三九已至劫流,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背祠汇。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工仍秤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人可很。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓诗力,卻偏偏與公主長得像,于是被迫代替她去往敵國和親我抠。 傳聞我的和親對象是個殘疾皇子苇本,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容