仅用几行代码就撸了个数据库!

网友投稿 480 2023-03-27

本站部分文章、图片属于网络上可搜索到的公开信息,均用于学习和交流用途,不能代表睿象云的观点、立场或意见。我们接受网民的监督,如发现任何违法内容或侵犯了您的权益,请第一时间联系小编邮箱jiasou666@gmail.com 处理。

仅用几行代码就撸了个数据库!

最近重读《数据密集型应用系统设计》这本书,看到第三章《数据存储与检索》,主要讲数据库内部的索引技术。

从本质上讲,数据库主要是做两件事情:

当你给它数据时,它帮你保存数据(存储);当你查询数据时,它帮你取回数据(检索);

这两件事情看似简单,背后却暗含玄机。那么,数据库内部到底是如何存储数据的呢?又是如何检索数据的呢?

你可能会有这样的疑问:我作为一个开发人员,为什么需要知道数据库内部是怎么工作的呢?

我们显然不会自己从零开始,撸一个存储引擎。但由于市面上有太多数据库产品,我们需要从中挑一个最适合自己应用场景的。为了提高性能,我们也需要根据应用负载特征,对数据库进行调优。因此,必须对数据库底层技术有一些了解,知道它在背后都干了什么。

根据应用负载特征,数据库大致可以分为两种:

一种针对 在线事务型 业务,多采用 行式存储 方式;一种针对 离线分析型 业务,多采用 列式存储 方式;

为了提高检索速度,索引必不可少。不同存储引擎采用的索引技术也不太一样,大致可以分为两种:

日志式存储引擎( log-structured ),比如 LSM树 ;页式存储引擎( page-oriented ),比如 B树 ;

为了引出这些概念,作者用几行 Shell 代码,写了一个玩具数据库抛砖引玉:

#!/bin/bash  db_set() {     echo "$1,$2" >> database }  db_get() {     grep "^$1," database | sed -e "s/^$1,//" | tail -n 1 }

这两个简短的 Shell 函数实现了一个 KV 式数据库引擎。麻雀虽小,五脏俱全!它提供了两个基本操作:

db_set ,保存键值对数据,即将键值用逗号分隔追加到名为 database 的数据文件;db_get ,按键取出对应的数据,即从 database 文件中过滤出最后一行包含指定键的数据;

这个玩具数据库可以这样用,比如保存键值对数据:

数据最终保存在 database 文件中,每个键值对一行,格式大致长这样:

随后可以这样查询数据:

修改数据时,新记录被追加到 database 文件末尾,旧数据不会删:

因此,我们查询数据时,db_set 最后需要执行 tail 命令,以最新的那条为准:

fasion@SmartPro [ ~ ]  ➜ db_get 3 Python源码深度剖析

这个玩具看上去挺有意思的,但它的性能到底如何呢?

db_set 操作的性能非常好,因为它只是将数据记录追加到 database 文件的末尾,这通常都很快。

跟 db_set 类似,很多数据库内部也有一个只追加的数据文件,一般叫做操作日志。虽然实际数据库需要考虑更多因素,包括并发控制、磁盘空间重用、错误处理等等,但基本原理都是一样的。

然而,如果数据库中有大量数据,db_get 操作的性能会非常差。因为每次你查询一个键,db_get 都必须扫描整个数据库文件!这是一个典型的 操作,数据库记录数增加一倍,查询开销就会增大一倍!这可不太好!

为了在数据库中快速检索数据,我们还需要另一个数据结构:索引 。索引是一些额外的元数据( metadata ),就像路标一样,可以帮我们快速定位数据。如果你的数据有多种查询条件,则可能需要建多个索引。

索引可以加快查询,但也会带来额外的开销,特别是对写操作。任何索引都会降低写性能,因为每次数据写入后,都要更新索引。因此,每个存储系统都需要根据实际情况做出权衡:

索引选得好可以加快查询;索引一定会降低写性能;

因此,数据库通常不会默认建好索引,需要开发人员或数据库管理员自行选择。想要以最小的代价换取最大收益,不仅需要对应用的查询模式有准确把握,还需要对数据库内部索引技术有一定了解。

上一篇:大连社保保民生 北塔BTIM保综合运维管理
下一篇:告警确认不及时分析(告警确认是什么意思)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~