隨著業(yè)務(wù)越來越看重數(shù)據(jù)的重要性顿乒,相信大家也做了很多
多維分析
的需求刷允,在調(diào)研技術(shù)選型時候,會發(fā)現(xiàn)很多olap
恩掷,如druid
倡鲸、clickhouse
馋袜、starRocks
都是列式存儲數(shù)據(jù)庫闽坡,今天我們來通過對比行存儲簡單說下列存儲
舉個栗子來說下列存儲和行存儲
要過年回家了,今天做了核酸檢測泊窘,我們就以存儲核酸檢測為業(yè)務(wù)場景
栗子
- 就以應(yīng)用頁面為主逼争,存儲核酸記錄需要存儲以下幾個字段
-
姓名
优床、身份證號
、檢測機構(gòu)
誓焦、檢測時間
羔巢、結(jié)果
、價格
行存儲
在行存儲下(如mysql等)罩阵,大家都比較熟悉,就不多說了启摄,每條記錄都是表中的每一行稿壁,表存儲如下
|姓名
|身份證號
|檢測機構(gòu)
|檢測時間
|結(jié)果
|價格
|
|-----|-----|--|----------|-----|-----|
| 彥祖 | 123512387 | 北京 | 2021-12-24 12:12:45 | 陰性 |35|
| 德華 | 213124157 | 上海 | 2021-12-22 12:12:45 | 陰性 |20|
| 路人甲 | 213123145 | 河南 | 2021-12-21 12:12:45 | 陰性 | 8 |
| 德華 | 213124157 | 廣州 | 2021-12-29 12:12:45 | 陰性 | 23|
| 彥祖 | 123512387 | 上海 | 2021-12-30 12:12:45 | 陰性 | 20|-
因為數(shù)據(jù)都是按行方式存儲,所以在物理存儲中歉备,會以連續(xù)空間來存儲數(shù)據(jù)傅是,物理存儲中,這些數(shù)據(jù)存儲方式如下:
行存儲物理結(jié)構(gòu)
行存儲優(yōu)點分析
- 在這樣的物理結(jié)構(gòu)下蕾羊,因為是連續(xù)空間喧笔,所以插入一條數(shù)據(jù)只需要追加到當前數(shù)據(jù)之后即可,很方便
- 對于按記錄查詢也很方便龟再,例如:我們要查詢彥祖的所有核酸記錄书闸,頁面應(yīng)用的話應(yīng)該是通過彥祖的身份證號
- 對應(yīng)的sql如下:
select * from 核酸記錄表 where 身份證號='彥祖的身份證號'
- 這個sql的執(zhí)行流程比較清晰
1.先從索引查詢出來彥祖的記錄存儲的物理地址
2.在通過物理地址去表的物理存儲中查詢對應(yīng)地址中的數(shù)據(jù)
- 這樣就可以快速得到彥祖的核酸記錄
行存儲缺點分析
- 這時候,業(yè)務(wù)方提了一個需求利凑,他要統(tǒng)計彥祖做核酸總共花了多少錢
- 對于這個需求浆劲,sql實現(xiàn)也很簡單,通過對
價格
列sum
就可以實現(xiàn)哀澈,sql如下:
select sum(價格) from 核酸記錄表 where 身份證號='彥祖的身份證號'
- 這個sql的執(zhí)行流程也比較清晰
1.先從索引查詢出來彥祖的記錄存儲的物理地址
2.在通過物理地址去表的物理存儲中查詢對應(yīng)地址中的數(shù)據(jù)
3.拿到所有數(shù)據(jù)時候牌借,在通過對于價格列sun聚合得到結(jié)果
- 分析下,因為行存儲使用的是連續(xù)空間割按,即使需求里面只需要
select sum(價格)
膨报,但是讀取物理存儲時候,還是讀取出來了所有的字段
行存儲優(yōu)缺點總結(jié)
- 通過上面的分析,總結(jié)一下行存儲的優(yōu)缺點
-
優(yōu)點
:
1.連續(xù)空間對于插入/更新很方便
2.對于記錄查詢很方便
缺點
1.會查詢出來很多不需要的列
列存儲
姓名 |
身份證號 |
檢測機構(gòu) |
檢測時間 |
結(jié)果 |
價格 |
---|---|---|---|---|---|
彥祖 | 123512387 | 北京 | 2021-12-24 12:12:45 | 陰性 | 35 |
德華 | 213124157 | 上海 | 2021-12-22 12:12:45 | 陰性 | 20 |
路人甲 | 213123145 | 河南 | 2021-12-21 12:12:45 | 陰性 | 8 |
德華 | 213124157 | 廣州 | 2021-12-29 12:12:45 | 陰性 | 23 |
彥祖 | 123512387 | 上海 | 2021-12-30 12:12:45 | 陰性 | 20 |
- 在列存儲中现柠,對于同樣的核酸記錄表院领,存儲的物理結(jié)構(gòu)如下:
- 在列式存儲中,會把每一列存儲到一起晒旅,如
姓名
列栅盲,是把所有記錄中的姓名
這列的值使用連續(xù)空間存放到一起 - 而對于各個列之間,是沒有必要使用連續(xù)空間存放到一起的废恋,所以很多列式數(shù)據(jù)庫都使用了分布式存儲的方式谈秫,存儲各個列
- 下面我們來分析下列存儲的
數(shù)據(jù)壓縮
和查詢執(zhí)行流程
列存儲的數(shù)據(jù)壓縮
- 很多列式數(shù)據(jù)庫都是通過
字典表
的方式進行數(shù)據(jù)壓縮
- 因為是把每一列存放到一起的,所以很容易通過對于每一列進行去重鱼鼓,來構(gòu)建一個字典表拟烫,例如:
- 對于
姓名
列,這列的所有數(shù)據(jù)如下:
彥祖|德華|路人甲|德華|彥祖
- 對這列值去重以后迄本,構(gòu)建一張
姓名
列字典表
硕淑,構(gòu)建算法忽略,就使用自增id的方式,如下:
|id
|姓名列
|
|-----|-----|
|1| 彥祖 |
|2| 德華 |
|3| 路人甲 | - 這樣構(gòu)建字典表嘉赎,對于列存儲的物理存儲結(jié)構(gòu)置媳,就可以執(zhí)行存儲字典表中的id,而不用存儲具體的值,有了字典表以后
姓名
列存儲如下:
1|2|3|2|1
- 同樣對于
價格
列公条,這列的所有數(shù)據(jù)如下:
35|20|8|23|20
對這列值去重以后拇囊,構(gòu)建一張
價格
列字典表
,構(gòu)建算法忽略靶橱,就使用自增id的方式,如下:
|id
|價格列
|
|-----|-----|
|1| 35 |
|2| 20 |
|3| 8 |
|4|23|有了字典表以后
價格
列存儲如下:
1|2|3|4|2
- 這樣通過一些數(shù)據(jù)壓縮算法等寥袭,可以對數(shù)據(jù)存儲進行壓縮
列存儲的查詢執(zhí)行過程
- 有字典表以后,我們來看下关霸,列存儲一般是如何進行查詢的
- 業(yè)務(wù)需求查詢
彥祖
传黄,20塊錢
做的核酸記錄:
select * from 核酸記錄表 where 姓名=彥祖 and 價格=20
- 對于該sql,執(zhí)行過程如下:
1.對于where 姓名=彥祖
首先查詢姓名字典表队寇,查詢到彥祖的id=1
id |
姓名列 |
---|---|
1 | 彥祖 |
2 | 德華 |
3 | 路人甲 |
2.通過查詢到彥祖的id膘掰,對于性名列進行對比,構(gòu)建一個bitmap佳遣,把匹配的要的列的索引位設(shè)置為1炭序,否則為0
3.對于where 價格=20
和上面一樣的操作,先查詢價格字段表苍日,20的id=2
id |
價格列 |
---|---|
1 | 35 |
2 | 20 |
3 | 8 |
4 | 23 |
4.通過查詢到價格20的id惭聂,對于價格列進行對比,構(gòu)建一個bitmap相恃,把匹配的要的列的索引位設(shè)置為1辜纲,否則為0
5.對于兩個where條件的結(jié)果bitmap做與運算,bitmap中,位為1的索引就是要查詢數(shù)據(jù)的所有列的索引,如該栗子中耕腾,兩個結(jié)果bitmap與運算后的結(jié)果是00001见剩,所以所有列的第5個值,拼接起來就是我們要查詢的數(shù)據(jù)
6.所以我們把所有列的第五個值拿出來組裝后就是我們需要的數(shù)據(jù)
列存儲優(yōu)點分析
- 上面講了列存儲的
數(shù)據(jù)壓縮
,在數(shù)據(jù)壓縮上列存儲有一定的優(yōu)勢 - 每一列都可以天然做索引扫俺,不需要額外的數(shù)據(jù)結(jié)構(gòu)來對各個列構(gòu)建索引苍苞,所以不用在意每一列的數(shù)據(jù)類型,都可以做索引
- 對于統(tǒng)計彥祖做核酸總共花了多少錢這種需求
select sum(價格) from 核酸記錄表 where 身份證號='彥祖的身份證號'
- 因為列是
分開存儲
的狼纬,按照上面講的查詢流程羹呵,其實最后我們得到的結(jié)果bitmap
,拿到位=1的索引
后疗琉,我們不需要查詢所有的列
冈欢,只需要拿著索引去價格列中獲取相應(yīng)位置的值,然后在進行sum聚合
列存儲缺點分析
- 因為各個列是分開存儲的盈简,所以在插入凑耻、更新時,需要對于
每一個列進行操作
柠贤,沒有行存儲連續(xù)空間
那么方便 - 還是看上面說的查詢過程香浩,每次查詢過后,都需要對查詢到的需要的列進行一個數(shù)據(jù)組裝
列存儲優(yōu)缺點總結(jié)
- 通過上面的分析臼勉,總結(jié)一下列存儲的優(yōu)缺點
-
優(yōu)點
:
1.數(shù)據(jù)壓縮比較有優(yōu)勢
2.任何列都可以做索引
3.查詢時只有涉及到的列會被讀取
缺點
1.每次查詢時邻吭,都需要對查詢到的列進行數(shù)據(jù)重新組裝
2.插入/更新操作比較困難
列式存儲數(shù)據(jù)庫就說到這里,歡迎大家來交流坚俗,指出文中一些說錯的地方,讓我加深認識岸裙,愿大家沒有bug猖败,謝謝!