導讀:在講《Apache Druid 底層存儲設計》時就說過要講一講列式存儲。如今來了,經過本文你能夠了解到行存儲模式、列存儲模式、它們的優缺點以及列存儲模式的優化等知識。算法
今日格言:不要侷限於單向思惟,多對比了解更多不一樣維度的東西。sql
咱們最早接觸的數據庫系統,大部分都是行存儲系統。大學的時候學數據庫,老師讓咱們將數據庫想象成一張表格,每條數據記錄就是一行數據,每行數據包含若干列。因此咱們對大部分數據存儲的思惟也就是一個複雜一點的表格管理系統。咱們在一行一行地寫入數據,而後按查詢條件查詢過濾出咱們想要的行記錄。數據庫
大部分傳統的關係型數據庫,都是面向行來組織數據的。如 Mysql,Postgresql。近幾年,也愈來愈多傳統數據庫加入了列存儲的能力。雖然列存儲的技術在十幾年前就已經出現,卻歷來沒有像如今這樣成爲一種流行的存儲組織方式。c#
行存儲和列存儲,是數據庫底層組織數據的方式。(和文檔型、K-V 型,時序型等概念不在一個層次)markdown
行存儲系統以行的方式來組織數據。假設如今有如下 blog 數據(大學時老師佈置系統課題做業老是讓咱們作一個博客系統,大概由於他們最早接觸的互聯網就是 BBS 吧):數據結構
[
{
"title": "Oriented Column Store",
"author": "Alex",
"publish_time": 1508423456,
"like_num": 1024
},{
"title": "Apache Druid",
"author": "Bob",
"publish_time": 1504423069,
"like_num": 10
},{
"title": "Algorithm",
"author": "Casey",
"publish_time": 1512523069,
"like_num": 16
}
]
複製代碼
行存儲將會如下列方式將數據存儲在磁盤上。咱們能夠思考一下,這樣的方式利於什麼樣的存儲?(此處停頓 5 秒思考一下)它利於數據一行一行的寫入,寫入一條數據記錄時,只須要將數據追加到已有數據記錄後面便可。oop
行模式存儲適合 OLTP(Online Transaction Processing)系統。由於數據基於行存儲,因此數據的寫入會更快。對按記錄查詢數據也更簡單。大數據
大部分同窗會問,咱們的作的系統不就是在爲了這個嗎?因此我爲何還須要列式存儲,而列式存儲又是什麼?優化
讓咱們想象一種場景,如今不是想查詢 Bob 的博客,我想統計 Bob 發表的博客數,或是整個系統今天的博客點贊數。若是是行存儲系統,數據庫將怎樣操做?(停頓思考 10 秒)ui
如圖,想統計全部點贊數,首先須要將全部行數據讀入內存,而後對 like_num 列作 sum 操做,從而獲得結果。咱們假設磁盤一次能夠讀取圖中 3 個方框的數據(實際須要按 byte 來讀取),那麼這個聚合計算須要 N(N=數據量)次磁盤訪問。
這種常常須要經過大量數據集來聚合統計數據的需求實際上是 OLAP 系統的常見行爲。基於這個需求咱們也能夠明白爲何這幾年列式存儲開始流行。由於數據,大數據,數據分析,也就是 OLAP(Online Analytical Processing)在線分析系統的需求增多了,數據寫入的事務和按記錄查詢數據都不是它的關注點,它關注的是數據過濾,統計。
一樣是上面的示例數據,咱們來看列式存儲是怎樣組織數據的。
[
{
"title": "Oriented Column Store",
"author": "Alex",
"publish_time": 1508423456,
"like_num": 1024
},{
"title": "Apache Druid",
"author": "Bob",
"publish_time": 1504423069,
"like_num": 10
},{
"title": "Algorithm",
"author": "Casey",
"publish_time": 1512523069,
"like_num": 16
}
]
複製代碼
如圖所示,列式存儲將每一列的數據組織在一塊兒。能夠思考一下這樣利於什麼呢?(停頓 5 秒)
是的,利於對於列的操做,如上面咱們說到的統計全部 like_num 之和。其過程將以下:
依然假設磁盤一次能夠讀取 3 個方框的數據(實際按 byte 讀取)。能夠看出按列存儲組織數據的方式,只須要 1 次磁盤操做就能夠完成。
在程序的世界裏,咱們學會了,任何的選擇和傾向都是有代價的。空間換時間,時間換空間,一致性可用性相互平衡等。選擇列式存儲必然也有不利的一面。首先就表如今數據寫入上。
當一條新數據到來,須要將每一列存儲到對應的位置。這樣就須要屢次寫磁盤操做。(固然真實的數據庫不會出現圖中」擠一擠「、」挪一挪「的狀況,數據庫會將不一樣列數據組織在不一樣的地方;對於屢次寫操做的問題,大部分存儲系統會經過緩衝來下降這種狀況帶來的不足)
Row-Store | Column-Store |
---|---|
由於按一行一行寫和讀取數據,所以讀取數據時每每須要讀取那些沒必要要的列 | 能夠只讀取必要的列 |
易於按記錄讀寫數據 | 對一個一個記錄的數據寫入和讀取都較慢 |
適合 OLTP 系統 | 適合 OLAP 系統 |
不利於大數據集的聚合統計操做 | 利於大數據集的數據聚合操做 |
不利於壓縮數據 | 利於壓縮數據 |
基於列模式的存儲,自然就會具有如下幾個優勢:
自動索引
由於基於列存儲,因此每一列自己就至關於索引。因此在作一些須要索引的操做時,就不須要額外的數據結構來爲此列建立合適的索引。
利於數據壓縮
利於壓縮有兩個緣由。一來你會發現大部分列數據基數實際上是重複的,拿上面的數據來講,由於同一個 author 會發表多篇博客,因此 author 列出現的全部值的基數確定是小於博客數量的,所以在 author 列的存儲上實際上是不須要存儲博客數量這麼大的數據量的;二來相同的列數據類型一致,這樣利於數據結構填充的優化和壓縮,並且對於數字列這種數據類型能夠採起更多有利的算法去壓縮存儲。
目前列存儲模式在不少分析型數據庫中都很常見。並且由於大數據分析型需求的增多,愈來愈多傳統的行存儲數據庫也加入了列存儲的模式,好比 Oracle 和 Sql Server 都有了列存儲的特性。
以前講的 Apache Druid 底層數據存儲就是基於列模式。有興趣的能夠回顧一下。另外 HBase 是一個比較有表明性的列存儲模式數據庫。有時間能夠來聊一聊 HBase 底層是如何存儲數據的。也能夠講一講數字列的壓縮方式(你們也能夠先思考一下能夠如何壓縮數字列)。
系列文章:
時間序列數據庫(TSDB)初識與選擇
十分鐘瞭解 Apache Druid
Apache Druid 底層存儲設計
Apache Druid 的集羣設計與工做流程
參考文章:
https://towardsdatascience.com/the-beauty-of-column-oriented-data-2945c0c9f560
https://dataschool.com/data-modeling-101/row-vs-column-oriented-databases/
想了解更多數據存儲相關知識,請關注個人公衆號。
本文使用 mdnice 排版