日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据库内核杂谈 - 一小时实现一个基本功能的数据库

發(fā)布時(shí)間:2025/4/14 数据库 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库内核杂谈 - 一小时实现一个基本功能的数据库 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

我們摒棄直接介紹數(shù)據(jù)庫內(nèi)核各個(gè)模塊的思路,而是從應(yīng)用開發(fā)者的角度出發(fā),來看實(shí)現(xiàn)一個(gè)數(shù)據(jù)庫需要哪些基本功能,然后把這些功能細(xì)分成最小的模塊再手把手一起實(shí)現(xiàn)。

對與應(yīng)用開發(fā)者而言,一個(gè)數(shù)據(jù)庫需要哪些必要的功能呢?

1)創(chuàng)建數(shù)據(jù)庫和數(shù)據(jù)表:create database,schema, table等
2)存儲數(shù)據(jù):insert /update數(shù)據(jù),或者從其他方式導(dǎo)入數(shù)據(jù)(比如csv文件)
3)讀取查詢數(shù)據(jù):通過SQL語句,對數(shù)據(jù)進(jìn)行讀取和查詢,比如sort,aggregate,filter等

因?yàn)橐蛿?shù)據(jù)庫交互,最必要的條件是有個(gè)客戶端程序可以接受用戶送來的指令。但要實(shí)現(xiàn)一個(gè)功能齊全的Parser可得花不少精力。內(nèi)核雜談,偷個(gè)懶,假設(shè)Parser已經(jīng)有實(shí)現(xiàn),從而把精力都關(guān)注在數(shù)據(jù)庫系統(tǒng)內(nèi)部的實(shí)現(xiàn)。拋開Parser,又該從哪開始呢?
思路是跟著數(shù)據(jù)的流向,自下而上,依次從存儲數(shù)據(jù),讀取數(shù)據(jù)和查詢數(shù)據(jù)來看。

創(chuàng)建和存儲數(shù)據(jù)
說到存儲,第一個(gè)想法就是文件系統(tǒng)(其實(shí)說到底數(shù)據(jù)庫系統(tǒng)就是一個(gè)特殊的文件系統(tǒng),區(qū)別與普通文件系統(tǒng)提供的的讀寫文件的接口,數(shù)據(jù)庫只是提供了一個(gè)面向數(shù)據(jù)的接口:存儲,讀取和查詢;整個(gè)系統(tǒng)為這些接口提供服務(wù))。

以student表作為示例,要怎么把這張表存在文件中呢?

最顯而易見的就是用Comma-separated value(CSV)格式存:

1,"Xiaoputao",3,"Hiking"
2,"Zgu",3,"Running"
3,"Xiaopang",2,"Walking"

讀取CSV文件的邏輯也非常簡單: 一行一行讀取數(shù)據(jù),然后根據(jù)";"把每個(gè)數(shù)據(jù)段取出。

除了CSV存儲,另一種常見的方式就是json格式:
[ {"id":1, "name":"Xiaoputao", "class":3, "hobby":"running}, ... ]

聊聊CSV和JSON存儲的優(yōu)缺點(diǎn)。兩者都屬于文本存儲,優(yōu)點(diǎn)一在于易于人類理解。另一個(gè)優(yōu)點(diǎn)就是直接兼容其他支持CSV和JSON的數(shù)據(jù)庫。缺點(diǎn)也很明顯,存儲效率不高,讀取效率也會隨之降低。另一個(gè)問題在于,上述例子中存儲的內(nèi)容只有值,沒有type和size(metadata),這些信息在后續(xù)操作如校驗(yàn)中是很重要的。當(dāng)然,我們可以把metadata加入到存儲中,比如,把json的每個(gè)val變成一個(gè)obj:{"colName":"id","colType":"int","colSize":4,"colVal":1}。
專業(yè)數(shù)據(jù)庫肯定不會選擇用CSV或JSON作為默認(rèn)存儲,但幾乎都支持CSV和JSON數(shù)據(jù)作為external table。如果要追求更高的性能,我們可以選擇更高效的編碼方式把數(shù)據(jù)以字節(jié)流的形式存儲在文件中;只要數(shù)據(jù)庫系統(tǒng)自身能夠讀取這些數(shù)據(jù)即可。
時(shí)間有限,當(dāng)然是一切從簡,就選擇CSV或者JSON的文件格式來存儲我們的數(shù)據(jù)。

只要有一個(gè)文本編輯器,能夠創(chuàng)建和編輯CSV或者JSON文件。這其實(shí)這已經(jīng)完成了創(chuàng)建數(shù)據(jù)表,輸入,修改以及存儲數(shù)據(jù)的功能。

讀取數(shù)據(jù)
基于上述用CSV或JSON的存儲,讀取數(shù)據(jù)非常簡單(允許我們調(diào)用第三方支持CSV或者JSON的API)。重點(diǎn)在于讀取完存放在怎樣一個(gè)數(shù)據(jù)結(jié)構(gòu)中方便后續(xù)對數(shù)據(jù)進(jìn)一步的查詢操作。根據(jù)數(shù)據(jù)的特性,結(jié)果集(RowSet)是由一序列的行數(shù)據(jù)(Row)組成,每一行又由多個(gè)單元(Cell)組成。我們試著根據(jù)這個(gè)概念設(shè)計(jì)下面這些類:

Cell, Row, RowSet Class
簡單梳理下,每個(gè)Cell存type,size,和value;Row存一整行cell;RowSet存一序列的Row。具體在實(shí)現(xiàn)中還有很多細(xì)節(jié)需要注意,如typecheck, 確保每行列數(shù)相同,等等,這里也一并從簡略過。定義了存儲方式和數(shù)據(jù)結(jié)構(gòu),具體數(shù)據(jù)讀取代碼如下;

讀取csvToRowSet和jsonToRowSet的實(shí)現(xiàn)只需要借助第三方CSV和JSON的類庫就能實(shí)現(xiàn),就不贅述代碼了。


執(zhí)行查詢
有了存儲和讀取,已經(jīng)可以把數(shù)據(jù)從文件中讀取到內(nèi)存,接下來就要支持用戶的查詢語句了。實(shí)現(xiàn)查詢就是去實(shí)現(xiàn)SQL語句中的各個(gè)功能模塊,比如排序(order by), 聚合(group by),多表聯(lián)合(join)等等。執(zhí)行器會對每個(gè)功能模塊進(jìn)行實(shí)現(xiàn),甚至針對不同的數(shù)據(jù)分布,會有多種方式的實(shí)現(xiàn)來提高讀取速度。現(xiàn)在,我們一起來討論一些常用的語言功能。

全表讀取(SELECT *)
其實(shí),定義了RowSet的數(shù)據(jù)結(jié)構(gòu)和實(shí)現(xiàn)了讀取文件的接口,我們的數(shù)據(jù)庫就已經(jīng)支持全表讀取的SQL語句,示例如下:

SELECT * FROM student;

分頁語句(LIMIT)
一下子就能想到的分頁語句,用來限制輸出的數(shù)據(jù)行數(shù):

Limit Operator
一行代碼,不解釋了。

關(guān)系映射語句(PROJECTION)
關(guān)系映射的本質(zhì)是對于輸入的RowSet的每一行(row), 通過各種標(biāo)量計(jì)算,輸出一個(gè)新的數(shù)據(jù)行,再由這些行組成新的RowSet。見下圖示例:

SELECT id + 5, LEN(name) FROM student;

對從student表讀取的每一行數(shù)據(jù),輸出一個(gè)新的數(shù)據(jù)行包含 id + 5 和 LEN(name)的cells。

Projection可以非常復(fù)雜,但有一條準(zhǔn)則就是它不改變原有RowSet的基數(shù)(cardinality), 即新RowSet的行數(shù)和原來的相同。因此,無論映射邏輯多復(fù)雜,輸入一個(gè)Row,輸出一個(gè)Row。再復(fù)雜的計(jì)算,也是一比一步迭代產(chǎn)生。比如上述示例可以分解成下面這些操作來完成:對于每一行input row, id值加5,對name取length,最后去掉class和hobby兩列。歸根結(jié)底就是將復(fù)雜的運(yùn)算拆分成原子操作然后一步一步地順序執(zhí)行。我們可以定義如下兩個(gè)基本operator:RowComputeOperator根據(jù)定義的computeCellVal對input row計(jì)算一個(gè)新cell,并把這個(gè)cell加到原row的末尾。SelectionOperator根據(jù)給定的indexes,生成一個(gè)僅包含指定index的新row。Pseudo code如下:

RowComputeOperator and SelectionOperator
RowComputeOperator里面有需要定義computeCellVal,輸入是一個(gè)row,輸出一個(gè)新的cell。具體實(shí)現(xiàn)則根據(jù)具體語義來定。定義一個(gè)computeCellVal需要2個(gè)參數(shù):1)運(yùn)算作用在哪些cell上,假設(shè)限制只能作用在1個(gè)或2個(gè)cell上(2個(gè)以上可以用多個(gè)Operator嵌套);2)提供具體計(jì)算的操作,比如常見單元操作如len(), ceiling(), abs()或者常見的二元操作如+-*/等等。

有了這兩個(gè)基本operator, 實(shí)現(xiàn)示例中的projection,我們定義3個(gè)operator即可:1)compute a new cell using "(id + 5)" 2) compute a new cell using "len(name)" 3) 用SelectionOperator選擇最后兩個(gè)新生成的cell。

實(shí)現(xiàn)整個(gè)projection的operator的pseudo code如下:

Projection Operator
條件選擇語句(WHERE)
有了Projection,我們就可以實(shí)現(xiàn)下面的條件選擇語句(WHERE)了:

SELECT * FROM student WHERE class = 3;

實(shí)現(xiàn)想法很簡單,首先用Projection operator計(jì)算出filter condition的值(bool),然后filter by 這個(gè)cell即可。

Filter Operator
排序語句(ORDER BY)
這里,我給一個(gè)非常低效但很容易理解的實(shí)現(xiàn):創(chuàng)建一個(gè)hashmap來存<cell, id>,然后對要sort的cell排序,根據(jù)cell順序取出原row組成新的rowSet輸出:

Sort Operator
有讀者會問,如果排序語句是一個(gè)expression而不是單個(gè)column怎么辦?比如下面的示例:

SELECT * FROM student ORDER BY id + 5 ASEC;

還記得我們前面實(shí)現(xiàn)的projection嗎?這里把(id + 5)作為一個(gè)新的projection加入到Row中即可。


一起實(shí)現(xiàn)了4個(gè)Operator,看看有沒有什么規(guī)律可循?所有定義的操作都是基于一個(gè)原則:輸入一個(gè)RowSet,然后輸出一個(gè)RowSet。并且,是一層一層循序漸進(jìn)的迭代。對于數(shù)據(jù)的查詢操作,是從最初讀取表中的原始數(shù)據(jù)開始,根據(jù)給定的Operator序列對數(shù)據(jù)逐一進(jìn)行操作;這一個(gè)Operator的輸出就是下一個(gè)operator的輸入。也就是說,給定一個(gè)SQL查詢語句,我們生成一序列Operator的tree,再依次執(zhí)行,就能得到最終結(jié)果。現(xiàn)在來一起優(yōu)化下代碼,把Operator的接口抽象出來,然后把剛才實(shí)現(xiàn)的operator全當(dāng)成子類來實(shí)現(xiàn)。代碼如下:

Unary Operator
疑問,基類為什么叫UnaryOperator呢?有了基類,我們可以根據(jù)SQL的語法功能實(shí)現(xiàn)相應(yīng)的Operator。

聚合操作(AGGREGATION)
接著一起來實(shí)現(xiàn)聚合操作。Aggregation分為兩大類,scalar-agg和multi-agg。scalar-agg就是簡單的sum, avg, min, max等的數(shù)據(jù)聚合操作,最終返回一個(gè)數(shù)據(jù)行的結(jié)果集,實(shí)現(xiàn)代碼如下:

Scalar-agg
每個(gè)AggOp接受一序列的cells,然后輸出聚合結(jié)果的cell。常見的AggOp如sum, max,min實(shí)現(xiàn)都很簡單,這邊就不贅述了。

multi-agg對應(yīng)SQL中的GROUP By,如下圖示例:

SELECT class_room, COUNT(*) FROM student;

比scalar-agg復(fù)雜的地方就是先要把有相同值的group by columns(示例中為class_rom)的row合并起來,然后對合并后的rows做Scala-agg即可。代碼我就不貼啦,當(dāng)留個(gè)小作業(yè)給大家。

SQL Operator Tree
有了實(shí)現(xiàn)基本語義的Operator,要實(shí)現(xiàn)一個(gè)完整的查詢語句,我們要做的就是把operator一層一層的累加起來,形成一個(gè)Operator tree,然后根據(jù)這個(gè)operator tree, 依次執(zhí)行每一個(gè)operator即可。比如下面這個(gè)查詢語句:

select class, sum(id + len(name)) as c

from (

? ? select * from student where hobby = 'hiking' limit 10

)

group by class;

我們只要建立如下的Operator tree:

sql operator tree
有沒有覺得挺神奇的!即使再復(fù)雜的查詢SQL都能這樣用基本的operator像搭樂高一樣搭建起來。

小結(jié)
至此,我們簡單的數(shù)據(jù)庫也實(shí)現(xiàn)得差不多啦。我看了下自己寫的pseudo code僅僅200多行,一個(gè)小時(shí)寫完也不算條件太苛刻。雖然數(shù)據(jù)結(jié)構(gòu)冗余,算法低效,但是麻雀雖小,五臟俱全!

為什么基類定義為UnaryOperator?因?yàn)槲覀冞€有BinaryOperator。二元的操作是做什么的呢?答案就是為了表與表的聯(lián)合(join)。有了Binary Operator,Operator的疊加就真正變成了一顆樹(二叉樹),這也是為什么前文我們稱之為operator tree。本文就先不詳述如何實(shí)現(xiàn)Join Operator了,以后會有專門的章節(jié)來覆蓋。再講下去,肯定超過一個(gè)小時(shí),讀者就更覺得我標(biāo)題黨了。

最后給大家總結(jié)一下:

1)一個(gè)SQL的查詢語句,即便邏輯再復(fù)雜,也可以拆分成一個(gè)一個(gè)原子operator的疊加
2)把這些operator組建成一個(gè)operator tree,然后自底向上地依次執(zhí)行,就能得到最終的查詢結(jié)果
3) 你可能覺得真正的數(shù)據(jù)庫和我們在這搗鼓的很不一樣。如果有條件,可以在Mysql或者Postgres中運(yùn)行"EXPLAIN SQL_STMT"來打印它們生成的operator tree,你會發(fā)現(xiàn)和我們生成的樹挺相似的

總結(jié)

以上是生活随笔為你收集整理的数据库内核杂谈 - 一小时实现一个基本功能的数据库的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 久久久无码18禁高潮喷水 | 欧美成人精品欧美一级乱 | 插吧插吧综合网 | 五月天精品 | 帮我拍拍漫画全集免费观看 | 国产精品高潮呻吟AV无码 | 欧美在线综合 | 精品第一页 | 干美女少妇 | 天天看夜夜爽 | 国产日本一区二区三区 | 波多野结衣爱爱 | 国产精品视频免费观看 | 国产高清黄色 | 国产91在线免费观看 | 99精品亚洲 | 国产视频一 | 亚洲综合精品在线 | 久久午夜精品人妻一区二区三区 | 中文字幕一区二区三区在线不卡 | 成人在线黄色 | 国产高清一区二区三区四区 | 69精品一区二区三区 | 免费黄色小视频 | 国产成人精品一区二区三区网站观看 | 欧美色图国产精品 | www.污网站 | 日韩欧美日本 | 国产精品久久免费视频 | 国产毛片基地 | 日日嗨av一区二区三区四区 | 成人免费看| 美女扒开尿口让男人桶 | 91在现看 | 中字av在线 | 中文有码在线 | 成人区人妻精品一区 | 激情免费视频 | 北京富婆泄欲对白 | 一本一道无码中文字幕精品热 | 中国免费毛片 | 日美韩一区二区三区 | 久久精品偷拍视频 | 久久久久久美女 | 日本黄色xxx | 天天干狠狠插 | 韩国毛片视频 | 午夜精品久久久久 | 夜夜嗨一区二区三区 | 久久亚洲免费视频 | 亚洲少妇精品 | 欧美不卡影院 | 一级二级在线观看 | jizzz18| 美女福利影院 | 天天操天天射天天爱 | 日韩精品免费一区二区三区竹菊 | 欧美xxxbbb | 国产91美女视频 | 久久亚 | 日本韩国欧美一区二区三区 | 极品销魂美女一区二区三区 | 精品一区二区三区视频在线观看 | 国产在线免费 | 九一在线视频 | 国产一级aa大片毛片 | 蜜桃在线一区二区三区 | 亚洲无码精品在线播放 | 西比尔在线观看完整视频高清 | 亚洲第一伊人 | 全国探花 | 久久久网址| 免费荫蒂添的好舒服视频 | 欧美色涩 | 成人瑟瑟| 国产一区999| 中出av在线| 草逼免费视频 | 看av网址| 老版k8经典电影 | 免费荫蒂添的好舒服视频 | 日韩a毛片| 久久一卡二卡 | 欧美视频在线观看一区二区三区 | 日韩黄色三级视频 | www.三级| 久久爱影视 | 久久精品综合视频 | 欧美综合一区二区三区 | 性欧美丰满熟妇xxxx性久久久 | 黄色片在线免费观看视频 | 国产一区一区 | 农村脱精光一级 | 天堂av网址 | 午夜视频福利在线 | 国产又粗又猛又爽又 | 日日插插 | 在线不卡av电影 | 免费av地址 |