专栏电商日志财经减肥爱情
投稿投诉
爱情常识
搭配分娩
减肥两性
孕期塑形
财经教案
论文美文
日志体育
养生学堂
电商科学
头戴业界
专栏星座
用品音乐

实现自己的数据库三

  一前言
  上篇实现了数据库的持久化,就是一个质的飞跃,虽然代码不复杂,但是对没有这方面经验者来说,还是意思的,下一步就是要完成另外一个飞跃,将存储的数据结构采用B树的形式来保存。在改造之前,还有些准备工作,一是将代码改动下,引入游标这个概念,二是对B树的结构和原理再做一次梳理,然后才能进入代码开发阶段。二游标cursor
  游标这个概念,再这里面可以抽象认为为指向一行的指针,通过这个指针我们可以做插入或查询、以及移动到下一行row等。定义结构如下:typedefstruct{Tabletable;uint32trownum;boolendoftable;Indicatesapositiononepastthelastelement}Cursor;
  定义内容比较简单,游标归属的表,归属的行号、是否为表的结尾,遍历时候使用,表结束后退出查询等。
  定义好游标,第一个想法可能是如何创建游标,由于游标可以用来遍历之用,我们在一些语言的集合遍历的时候也有定义类似Iter之类的,和游标类似,一般通过集合的start()行数创建,创建指向第一个元素,这里面的游标也是类似,start创建即指向第一个游标,end指向最后一个元素。Cursortablestart(Tabletable){Cursorcursor(Cursor)malloc(sizeof(Cursor));cursortabletable;cursorrownum0;cursorendoftable(tablenumrows0);returncursor;}Cursortableend(Tabletable){Cursorcursor(Cursor)malloc(sizeof(Cursor));cursortabletable;cursorrownumtablenumrows;cursorendoftabletrue;returncursor;}
  有了这个定义,我们就可以简化定位一行的操作,原来的核心行数:voidrowslot(Tabletable,uint32trownum)
  可以改成才有游标的形式:voidcursorvalue(Cursorcursor)
  里面的内容也需要按照数据结构做调整:voidrowslot(Cursorcursor){行号通过游标获取uint32trownumcursorrownum;uint32tpagenumrownumROWSPERPAGE;页面参数通过游标获取到table后再获取pagervoidpagegetpage(cursortablepager,pagenum);uint32trowoffsetrownumROWSPERPAGE;uint32tbyteoffsetrowoffsetROWSIZE;return(char)pagebyteoffset;}
  对于游标的递增,可以通过下面行数实现:voidcursoradvance(Cursorcursor){cursorrownum1;如果行数达到了表的最大行数,设置游标的表结束标志循环时候可以根据这个判断来决定是否结束if(cursorrownumcursortablenumrows){cursorendoftabletrue;}}
  对于我们原来的核心代码中的执行逻辑也要进行改动了,查询循环原来是按照行数遍历现在改成游标的方式,只所以用游标抽象一层,是因为我们通过游标可以封装后面的B树的遍历,而我们原来的遍历是和表的行紧密绑定的,这里面又包含了将容易改变的部分要抽离出来,整个架构依赖于抽象实现,抽象的具体实现,就可以根据需要灵活改动,而上层架构不受到影响,秒啊!ExecuteResultexecuteselect(Statementstatement,Tabletable){Rowrow;Cursorcursortablestart(table);for(uint32ti0;itablenumrows;i){deserializerow(rowslot(table,i),row);printrow(row);}直到游标是最后标记则结束while(!(cursorendoftable)){deserializerow(cursorvalue(cursor),row);printrow(row);游标向下移动一行cursoradvance(cursor);}returnEXECUTESUCCESS;}
  同样插入操作也要改动,首先我们获取需要插入的行,然后定义一个指向表结尾的游标,为什么要指向表结尾的游标那,因为我们的插入操作其实是一种追加,直接追加到最后一个,然后通过cursorvalue获取游标处的内存页,将表的行持久化到游标处的内存页中。ExecuteResultexecuteinsert(Statementstatement,Tabletable){if(tablenumrowsTABLEMAXROWS){returnEXECUTETABLEFULL;}Rowrowtoinsert(statementrowtoinsert);Cursorcursortableend(table);serializerow(rowtoinsert,cursorvalue(cursor));tablenumrows1;free(cursor);returnEXECUTESUCCESS;}
  获取游标处的内存操作如下,和原来类似,通过行号定位到属于哪个页面,通过行号定位到偏移量,如果仔细看的同学可能会发现,这里面的定位的时候是按照最后一行定位的,不应该是最后一行的下一行那,这里面实际没问题的,因为行的偏移量从0开始的,比如如果表里面只有一行数据,那表的rownum为1,则rownum为1的偏移量其实是没数据的,将数据插入到这个空闲位置没问题。voidcursorvalue(Cursorcursor){uint32trownumcursorrownum;uint32tpagenumrownumROWSPERPAGE;voidpagegetpage(cursortablepager,pagenum);uint32trowoffsetrownumROWSPERPAGE;uint32tbyteoffsetrowoffsetROWSIZE;return(char)pagebyteoffset;}
  游标抽象化之后测试:〔rootlocalhostmicrodb〕。a。outdb。mbmicrodbselect(1,a,aqq。com)(2,b,bqq。com)(1,a,aqq。com)(4,rrr,rrrqq。com)(5,ttt,tttqq。com)(6,d,dqq。com)(7,f,fqq。com)(8,g,gqq。com)(10,q,q163。com)Executed。microdbinsert11ddddqq。comExecuted。microdbselect(1,a,aqq。com)(2,b,bqq。com)(1,a,aqq。com)(4,rrr,rrrqq。com)(5,ttt,tttqq。com)(6,d,dqq。com)(7,f,fqq。com)(8,g,gqq。com)(10,q,q163。com)(11,dd,ddqq。com)Executed。microdb。exit〔rootlocalhostmicrodb〕。a。outdb。mbmicrodbselect(1,a,aqq。com)(2,b,bqq。com)(1,a,aqq。com)(4,rrr,rrrqq。com)(5,ttt,tttqq。com)(6,d,dqq。com)(7,f,fqq。com)(8,g,gqq。com)(10,q,q163。com)(11,dd,ddqq。com)Executed。microdbquitUnrecognizedkeywordatstartofquit。microdb。exit三B树3。1搜索
  我理解的搜索是从大量数据中提取所需要的数据,比如图书馆去找一本书,比如在一本书里面搜寻特定的关键词,那如何能快速搜索那,核心在于每步搜索都能快速缩减数据集合,仔细体会下,如果我们每步查询都可以将搜索的集合减少一半,那就是典型的二分法的搜索,那给我们一堆数据,比如以上设计的数据库,去搜索的时候,由于数据之间和位置之间是没有任何关系的,我们只能一行行遍历查询比较。但是这样的性能是和行数成正比的,即行数越多,我们需要查询的平均时间越长。
  有什么办法解决这个问题那,然我们用一组数据在内存中简单模拟下我们的表数据情况,如果要快速搜索这组数据,数据又很大的话,那么如果数据是排序的数组组成,我们可以通过二分法快速的找到所要的数据。但是如果用数组存储这组数据,在插入数据的时候,就需要将插入位置的元素都向后移动,导致插入的时候后面的元素都要向后移动一位。同样如果我们做删除操作,需要将删除位置的后面的数据向前移动,补上删除的空洞。
  从上面描述来看,用数组保存排序的数据,查询速度快,但是插入和删除太慢了。而想插入和删除的速度快,我们很容易想到的数据结构是链表,链表插入和删除都是更改指针的事情,比较简单,但是遍历的时候,我们只能沿着链表一个个去查,性能又和数据集合大小相关了。
  好吧,再思考下排序数组按照二分法来查找数据的场景,每次都可以将要搜索的数据集合缩小一半,那么我们是不是可以把单链表改造下,将排序链表从中间值提溜起来,中间值作为root节点,比root节点保存值小的,放在左边的链表中,比root值大的放在右边链表中,即变成一个二叉树,这样就变成了一个完全二叉树,插入和删除性能很高,查询的时候性能仍然很高(完全二叉树插入需要平衡,这个也影响了性能,所以设计了红黑树等取插入、删除、查询都均衡的数据结构)。
  二叉树的数据结构在内存中保存数据挺好,但是如果作为存在磁盘上的数据就有很多麻烦,二叉树每个节点最多有两个子树,如果数量大,导致整个树的高度比较高,树高了之后那,那需要指针就比较多,每次指针指向一个页面的话,导致需要从磁盘中读取N多个页面,这对我们搜索数据很不利。3。2B树和B树
  B树结构
  B树结构可以看作是二叉树的进化,我们的指针每次指向一个页面,因为一个磁盘的页面现在一般都是4KB大小,这个页面可以保存很多行数据,那我们的B树结构就可以在一个页面有多个分叉,一个页面又可以保存很多数据。
  数据的数据存储有的是B树,有的是B树这两者有何区别那,如下表:
  B树用来存储表数据的,Mysql的InnoDB引擎采用B树存储,多少个索引就多少个B树,数据存储在主键的B树上的,B树的内部节点只保存key,叶子节点是全部行数据,因为内部节点只保存key,所以一个节点可以保存更多的数据,而B树的节点保存不管是key还包含value,所以一个页面能存储的数量更少。B树的内部节点和叶子节点有相同的数据结构,而B树是不同的,B树内部节点保存的是key和指针数据,叶子节点是完整的多行数据。还要注意一点B树和B树的节点一般对应一个磁盘页面,页面内的数据是有序的。查找时候可以按照二分法进行查找。3。3m阶有序树
  我们刚才聊到B树或B树的可以有N多个子节点,节点内的数据又是有序的,我们可以叫做N阶排序树。这种树的内部节点和叶子节点是不同的,具体区别如下:
  内部节点存储的是key和指向子节点的指针,叶子节点保存的是key和value内部节点的保存key的数量最大为m1个,而叶子节点能保存多少保存多少内部节点保存指针的数量为key的数量1个,而叶子节点不保存指针。内部节点保存key的目的是为了路由,叶子节点保存key的目的是为了和value关联。内不能节点不保存value,而叶子节点保存value数据。3。43阶排序树的插入过程
  按照上述定义,我们来画图模拟三阶排序树的插入过程,三阶排序树有以下约束:每个内部节点最多保存三个子节点。每个内部节点最多保存二个key。每个内部节点至少有两个子节点。每个内不能节点至少有一个key。初始是一颗空树:
  这个空树直接作为没存任何数据的叶子节点。我们插入两个数据,如下:数据没超出三个数据的范围,我们将两条数据直接保存在这个节点上。
  假如一个节点只能保存2个数据,那么上述数据结构再插入一个数据后,会怎么办,只能分裂:我们插入数据后,由于不够保存,只能拆分上面的叶子节点,分成一个根节点和两个叶子节点,数据分到两个叶子节点上,根节点保存两个指针和一个key。查询的时候,找小于等于5的走左边的子节点,查大于等于5的,走右边的子节点。
  插入key2后,按照查找路由,找到叶子节点,但是叶子节点满了,只能分裂叶子节点,将原来的key5分裂到新的叶子节点上去,并对key2创建新的条目。
  继续插入18和21两条数据,树的结构变化如下:当插入21的时候,右边的叶子节点不够存储,如果再次创建叶子节点,则根节点要增加个指针,但是根节点也满了,需要将根节点再拆分,这样就增加了B树的高度。
  后续的B树的数据结构实现下篇幅再来聊聊。

使命召唤19测试奖励是什么?测试奖励公布一览COD19使命召唤19测试陆续开启,目前开启的是PS主机玩家,所有PS主机玩家都可以下载体验游戏了,紧接着是9月23日凌晨1点XBOX和PC预购玩家开启测试,公开测试是9月25日凌暗黑2今日mf成果老规矩,发图镇楼!摸了一把安姐,性感的安姐一声惨叫,给了华宁的保护提格莱特战甲,华宁的一套凑齐了。华宁的光辉巨皇冠防御增强一倍,抗寒减伤恢复生命,单独拿出来也可以给低级别佣兵使用。LOL下路理论组合类型详解昨天讲解了AD和辅助的类型,三种类型的ad和辅助刚好构成三种类型的组合。第一种击杀组合代表英雄德莱文锤石莎弥拉泰坦卡莎机器人优势拥有较强的先手能力和爆发伤害,很容易在前期打开局面。小予神带飞坏空空,伪五杀轻松拿下,赛后激情舞蹈把小予神看傻了新赛季开始后,小予神与坏空空一起双排,为了证明自己的实力,小予神掏出了自己的小国标马超,在游戏内各种秀操作,直接杀疯了,最后更是高地伪五杀轻松拿下这局比赛。而赛后坏空空也是现场来了羊了个羊爆火其实并非偶然大家好我是萌萌,话说最近是不是玩羊了个羊玩的有点上头,话说萌萌已经玩了几百次了,至今还是一次都没通关过,虽然这款游戏对运气的要求很高,但是我这智商真的是难以驾驭这样的小游戏啊。这两estar内讧前兆出现,评论区以海为核刷屏,要走20年的老路?KPL在2022年的KPL夏季赛结束后,其实并没有多少人在谈论这场比赛,毕竟挑战者杯的关注度并不高,更多的是一些八卦和八卦。最近整个KPL,都是关于estarpro的八卦。就像Al这4类菜要少吃,容易加重心血管负担,很多中老年人经常吃守护银龄世界俗话说,人与血脉同寿,意思是血管健康,人才会健康。很多人上了年纪之后就会受到一些心血管问题的困扰,但是心血管问题为何会来找你呢?其实多数是吃出来的!现代人对吃越来越讲究拒绝失传高血压其实是肾虚!八味药,补肾,降血压各位朋友,今天我来和您聊一个话题,这就是高血压。高血压是最常见的慢性病,也是心脑血管病最主要的危险因素,还伴有心脑肾等器官的功能或器质性损害的临床综合征。今天在这里,分享一张方子。一个通气散,上治耳鸣,中通肝气,下通肾气,气机一通,浑身轻松大家好,我是沈医生。今天给大家介绍一个妙方,只有三味药,上治耳鸣,中通肝气,下通肾气,气机一通,浑身轻松如果你出现了这种情况,总是唉声叹气,心情压抑,头疼头晕,耳鸣耳聋,视力下降,多喝热水竟然可能致癌!怎么喝水才最科学?喝水这件事,很多人都做错了!会喝比多喝更重要!3个误区,看看你中了几条都说女人是水做的,其实,不光女人是水做的,男人也是,人体大约65都是水,多喝水自然也成了保健养生的关键一环。但普尔续约的事情不会影响我,我没有上限勇士后卫乔丹普尔近日接受了记者采访。谈到对续约的看法,普尔表示上赛季我们做了球队需要做的,拿到了冠军。显然这件事还没解决,但我会让我的团队去处理。我有信心我们能解决这个问题。我不会
搞笑合集如果一个男生三天都没告诉你身高,那他一定没有180这是蚊子做的唯一一件好事。连词造句,看谁能回答出来。小姐姐,你快来解决一下我,救命啊。这个照片不知道符不符合你的要求。这样换一下是不是就能找得开了。你捡到了九千块钱,失主却说他丢了你了解动漫这一种新的影视形式吗?关于动漫动漫,即动画漫画的合称,指动画与漫画的集合,取这两个词的第一个字合二为一称之为动漫。动漫与游戏无关,并非专业术语。有的动漫IP与游戏相结合,是一种创新形式。通过这样的形式动罗马诺迪马利亚将在本周就尤文的报价给予最终答复直播吧6月20日讯据知名记者罗马诺消息,阿根廷前锋迪马利亚将在本周对尤文的报价做出最终答复。上赛季结束后,迪马利亚与巴黎圣日耳曼完成了告别,外界认为他的下一站普遍是尤文图斯。不久前白鞋脏了黄了别用水洗,教你正确做法,白鞋立马洁白如新虽然一年四季各有各的美,但是夏天应该是一年四季里最鲜艳的一个季节,在这个季节花朵争相开放,绿树成荫。人们都穿上自己颜色鲜艳好看的衣服,走在大街上,每个人都是一道亮丽的风景线,但是要世界谍战著名间谍大揭秘谍海纵横之东方魔女川岛芳子(下)策划一二八事变1931年9月18日晚10时20分,鞋扎在中国境内的日本关东军炸击了其所占据的柳条湖附近南满铁路的一段铁轨,反语中国士兵所为,并以此为借口突然表击沈阳北大营驻军,这就不提环保了?德国准备多烧煤来发电据新加坡联合早报网站报道,减少进口俄罗斯天然气供应后,德国政府将采取紧急措施,包括增加煤炭(火力发电)的使用,确保能源需求不受影响。报道称,德国经济部在19日的一份声明中说为了减少厦门与金门近在咫尺柯文哲建金夏大桥金门问题解决一半中国台湾网6月20日讯综合台湾中央社台湾联合报报道,柯文哲18日前往金门,为其担任党主席的台湾民众党金门联络处主持揭牌典礼。在谈到现在两岸的紧张气氛,他表示,厦门与金门近在咫尺,做8天9位名人相继去世,最小者仅37岁,有3人同一天离世6月还没过完,文艺界就先后传出了多位名人去世的消息。其中,从6月11日到6月18日,短短8天的时间,竟有9位名人相继离世。甚至,还有三位名人在同一天离世。他们的离去,是文娱界的损失是否有球队招募自己?比尔很多但你知道我不能告诉你名字直播吧6月19日讯今日奇才球星比尔参加了华盛顿班纳克(社区)篮球场翻新工程的剪彩仪式并接受了记者采访。当被问及自己对自由球员市场的预期时,比尔表示也许会很疯狂吧,就像往常一样。当被LamResearch半导体五大设备当中最低调的公司LamResearch半导体是五大设备当中最低调的公司。LamRESEARCH(柯林研发)由美国香港人DavidLam于1984年创立。Lam可以理解为大陆林姓衍生出来的公司。(林重磅表态!美得州共和党人宣布拒绝接受拜登为合法总统据路透社报道,在美国国会就2021年年初国会骚乱举行公开听证会之际,得克萨斯州的共和党人正式宣布总统拜登非法赢得2020年总统选举。报道称,美国得州共和党人当地时间19日在一个全州
友情链接:快好找快生活快百科快传网中准网文好找聚热点快软网