在上一篇的笔记之中,我们讨论了数据模型和查询语言。在第三章之中我们来聊一聊不同的数据引擎内部是如何实现存储和检索的,以及不同设计之间的折中与妥协。

1.键值对数据库

键值对数据库是数据库形式之中最简单的一种模式,我们可以把它简化的实现为下面两个函数:



底层存储格式也十分简单:一个文本文件,其中每行包含一个键值对,用逗号分隔(类似于CSV文件,忽略转义问题)。每一次调用 db_set 会追加键值对到文件的末尾,如果你更新的一个键值对的旧版本不会覆盖之前的键值对,但是 db_get会利用 tail -n 1 in 语句读取最新的键值对。但是真正的数据库需要处理更多的问题(例如并发控制、回收磁盘空间、使日志不能永久增长、处理错误和部分写的问题),但基本设计思路和原则是相同的。

但是,db_get 在性能上表现的很糟糕,每一次需要查找一个key,db_get 会扫描整个数据库文件来查找Key。在算法定义之中,查找的时间复杂度是O(n)。为了有效地查找数据库中某个特定键的值,我们需要一个不同的数据结构:索引

2.索引

索引是从原始数据派生出来的附加结构。在添加和删除索引时,不会影响数据存储的内容,它只会影响查询的性能。但是维护额外的结构会导致开销,尤其是写操作。任何类型的索引都会减慢写速度,因为每次写入数据时也需要更新索引。

在存储系统的有一个重要的权衡:精心挑选的索引加快了读取的速度,但是每个索引都会减慢写入速度。由于这个原因,数据库通常不会默认索引所有内容,但要求应用程序开发人员或数据库管理员手动地选择索引,可以选择使应用程序受益最大的索引,而不需要引入更多的开销。

  • 哈希索引

    这里我们通过哈希索引来分析一下上文提及的那个简易的键值数据库。最简单的索引策略是:保持一个内存的哈希映射,其中每一个键都映射到数据文件中的字节偏移量,通过偏移量可以找到该值的位置,如下图所示:



    每当向文件追加一个新的键值对时,也会同时更新哈希映射以反映刚才写入的数据的偏移量(这既可以用于插入新的键值对,也可以用于更新现有的键值对)。在查找值时,使用哈希映射查找数据文件中的偏移量,查找该位置并读取该值。

    那么我们如何避免最终耗尽磁盘空间呢?一个好的解决方案是,我们可以对这些文件执行压缩,如下图所示。压缩意味着在文件中扔掉重复的键,并且只保留每个键的最新更新。



    合并和压缩可以由后台线程完成,并且在进行合并和压缩操作时,我们仍然可以使用旧的文件继续正常地服务读写请求。在合并过程完成后,我们将读取请求转换为使用新合并的文件,然后旧的文件可以简单地删除。

    缺点

    (1)哈希索引严重依赖于内存,所以如果Key的数量庞大,需要匹配足够的内存空间。

    (2)范围查询效率不高,每查找一个值都需要一次键值对映射。
  • SSTable

    由哈希索引我们可以引申出更加高效的索引结构:SSTable(Sorted String Table),SSTable要求键值对序列按照键来排序。乍一看,这个要求似乎破坏了顺序写的性能,但是它大大提高了维护数据以及索引结构的效率。

    • 合并文件既简单又高效,使用简单的归并排序算法。

      • 不再需要保留所有键在内存中的索引,只需要保留部分键的索引,利用键在SSTable之中有序的特点。

      • 可以进行分组压缩,每个索引可以指向压缩块的起始点,来节省存储空间与减少I/O带宽的使用。

但是,如何让我们写入的键值对有序呢?这个问题在内存之中并不是什么难事,如红黑树AVL树这些数据结构,可以按任何顺序插入键,并按排序顺序读取它们。所以我们在使用SSTable时,会维护一个MemTable的数据结构在内存之中,当MemTable达到阀值时,我们将MemTable作为一个新的SSTable序列化到磁盘之上。同时利用后台线程,不断压缩删除旧的SSTable,来维护一个可循环运行的存储系统。由于两次写入一次是在内存,一次磁盘写入是连续的(append日志),因此SSTable可以支持非常高的写入吞吐量。

许多数据库都是采用这样的思路来高效的处理数据,如CassandraHBaseLevelDBBitcask等。Lucene的全文搜索的使用ElasticsearchSolr索引引擎,也采用了类似的方法来存储它的词典,当然,全文索引比键值索引复杂得多,但基于一个类似的想法:给定搜索查询中的一个词,查找提及该词的所有文档(Web页面、产品描述等)。这同样是一个键值结构实现的,其中键是一个词,而这个值是包含该词的所有文档的ID列表。

  • B树索引

    这个索引结构大家应该非常熟悉了,在关系型数据库(如:MySQL,Oracle)与非关系型数据库(如:MongoDB)之中都大量应用。B树也把键值对进行了排序,它既允许高效的值查询也允许高效的范围查询。

    哈希索引结构将数据分解成可变大小的段,通常是几个兆字节或更多的大小。而相比之下,树型索引将数据分成固定大小的块或页,通常为4KB大小(有时更大),每次读或写都基于页的大小。这种设计更接近于底层硬件,因为磁盘也是按固定大小的页来排列的。B树索引保证了:N个键总是有深度的O(log n)树,大多数数据都可以放入到一个三或四层的B树之中,(一个4页的四级树,分支系数为500,可以存储256TB)。下图展示了我们怎么样使用B树来查找“251”这个键:



    基本写的操作是覆盖旧数据的数据页,重写不会改变页的位置;即,当页被覆盖时,对该页的所有引用都保持不变。这与SSTable这样的哈希索引结构形成鲜明对比,它有附加操作,但从不修改文件。

    而B树索引的并发控制相对复杂,当多个线程会对树进行访问时,需要通过用锁存器(轻量级锁)保护树的数据结构来完成。(这里也可以用Copy on Write来快照隔离)而哈希索引结构的压缩,合并则不会影响查询,写入等操作。

  • 一些优缺点的探讨

    (1)顺序写入通常比随机写入快得多,所以SSTable通常的写入性能是相对优秀的。

    (2)由于SSTable压缩与清理的线程存在,通常会有较低的存储开销。但是压缩和清理磁盘的过程之中会与正常的请求服务产生磁盘竞争,导致吞吐量的下降。

    (3)由于SSTable会存在同一个键值的多个副本,对于实现事务等对于一致性要求更高的场景,树型索引会表现的更加出色。

3.小结

树型索引在数据库架构是非常根深蒂固的,对于很多的工作负载提供始终如一的良好性能。而以SSTable为代表的哈希索引也越来越受欢迎。确定哪种类型的存储引擎更适合应用场景,并没有一个简单易用的规则,因此需要我们对业务逻辑有更深层次的理解。

存储与索引------《Designing Data-Intensive Applications》读书笔记3的更多相关文章

  1. python for data analysis 2nd 读书笔记(一)

    第一章相对简单,也么有什么需要记录的内容,主要用到的工具的简介及环境配置,粗略的过一下就行了.下面我们开始第二章的学习 CHAPTER 22.2Python Language Basics, IPyt ...

  2. 【索引】Objective-C基础教程-读书笔记

    第1章 启程 http://www.cnblogs.com/duxiuxing/p/5492219.html 第2章 对C的扩展 第3章  面向对象编程的基础知识 第4章 继承 第5章 复合 第6章 ...

  3. 可靠的、可扩展的、可维护的数据系统 ------《Designing Data-Intensive Applications》读书笔记1

    坦白说也是机缘巧合,在硕士生阶段进入分布式系统领域学习.无论是大规模存储或计算,其核心也是运用分布式技术利用并行性来解决数据密集型应用的需求.最近开始在啃这本<Designing Data-In ...

  4. 副本机制与副本同步------《Designing Data-Intensive Applications》读书笔记6

    进入到第五章了,来到了分布式系统之中最核心与复杂的内容:副本与一致性.通常分布式系统会通过网络连接的多台机器上保存相同数据的副本,所以在本篇之中,我们来展开看看如何去管理和维护这些副本,以及这个过程之 ...

  5. 数据模型与查询语言 ------《Designing Data-Intensive Applications》读书笔记2

    数据模型是开发软件的最重要的部分,因为它们对应用程序有着深远的影响:不仅是软件的编写方式,而且也影响我们如何解决的问题的方式.第二篇读书笔记,我们聊一聊数据模型的设计. 1.数据模型的分层 作为一个开 ...

  6. OLAP与数据仓库------《Designing Data-Intensive Applications》读书笔记4

    由于第三章的内容比较多,这里我们拆分成两篇读书笔记来记录.上一章我们聊了聊如何数据库是如何实现存储和检索的,今天这篇我们继续来看看OLTP与OLAP存储引擎的区别与联系. 1.OLTP与OLAP 联机 ...

  7. 【MySQL 读书笔记】普通索引和唯一索引应该怎么选择

    通常我们在做这个选择的时候,考虑得最多的应该是如果我们需要让 Database MySQL 来帮助我们从数据库层面过滤掉对应字段的重复数据我们会选择唯一索引,如果没有前者的需求,一般都会使用普通索引. ...

  8. 【MySQL 读书笔记】当我们在使用索引的时候我们在做什么

    我记得之前博客我也写过关于索引使用的文章,但是并不全面,这次尽量针对重点铺全面一点. 因为索引是数据引擎层的结构我们只针对最常见使用的 Innodb 使用的 B+Tree 搜索树结构进行介绍. 每一个 ...

  9. mongodb底层存储和索引原理——本质是文档数据库,无表设计,同时wiredTiger存储引擎支持文档级别的锁,MMAPv1引擎基于mmap,二级索引(二级是文档的存储位置信息『文件id + 文件内offset 』)

    MongoDB是面向文档的数据库管理系统DBMS(显然mongodb不是oracle那样的RDBMS,而仅仅是DBMS). 想想一下MySQL中没有任何关系型数据库的表,而由JSON类型的对象组成数据 ...

  10. Mysql实战45讲 04讲深入浅出索引(上)读书笔记 极客时间

    极客时间 Mysql实战45讲 04讲深入浅出索引 极客时间(上)读书笔记  笔记体悟 1.索引的作用:提高数据查询效率2.常见索引模型:哈希表.有序数组.搜索树3.哈希表:键 - 值(key - v ...

随机推荐

  1. 关于 ElesticSearch 安装

    ElesticSearch windows 下安装步骤 1. 配置 JAVA_HOME 环境变量,因为作者是一个java开发人员,这是基本配置,就不多做赘述 2. 安装ElasticSearch 从官 ...

  2. linux C/C++开发环境搭建指南

    一.安装基本开发环境 1.配置GCC 刚装好的系统中已经有GCC了,但是这个GCC什么文件都不能编译,因为没有一些必须的头文件,所以要安装build-essential这个软件包,安装了这个包会自动安 ...

  3. 【分享】jQuery无插件实现 鼠标拖动图片切换 功能

    前言 我就想随便叨逼叨几句,爱看就看几句,不爱看就直接跳过看正文就好啦~ 这个方法是仿写页面时我自己研究出来,可能有比我更简单的方法. 但我不管,因为我没查我不知道,我就觉得我的最好啦,耶耶耶~ 效果 ...

  4. 如何基于 eolinker 的进行接口管理

    由于工作的原因,经常要接触到很多API接口,而API接口在设计时往往需要编写大量的文档,而且编写完成后往往需要根据实际情况,经常改动文档,这使得文档编写维护工作量相对较大,这让我也包括很多的开发者都很 ...

  5. ssh远程登录,禁止root登录

    1,useradd xiaobingpasswd xiaobing (设置密码) 2,禁止root登陆,修改 /etc/ssh/sshd_configPermitRootLogin yes 改为 Pe ...

  6. springboot使用i18n时properties文件中文乱码

    在springboot使用i18n进行国际化文件配置时,文件名为messages_zh_CN.properties的文件中填写中文信息,当使用浏览器进行访问时,出现中文乱码,此时在idea中进行修改s ...

  7. Chrome 浏览器报 filed to load resource:net err cache read failure 错误:

    在IE/FF下没有该错误提示,但在Chrome下命令行出现如下错误信息: Failed to load resource: net::ERR_CACHE_MISS 该问题是Chrome浏览器开发工具的 ...

  8. C语言之浮点数

    #include<stdio.h> int main(){printf("请分别输入身高的英尺和英寸," "如输入\"5 7\"表示5英尺 ...

  9. leetcode#42 Trapping rain water的五种解法详解

    leetcode#42 Trapping rain water 这道题十分有意思,可以用很多方法做出来,每种方法的思想都值得让人细细体会. 42. Trapping Rain WaterGiven n ...

  10. c语言贪吃蛇详解-2.画出蛇

    c语言贪吃蛇详解-2.画出蛇 前几天的实验室培训课后作业我布置了贪吃蛇,今天有时间就来写一下题解.我将分几步来教大家写一个贪吃蛇小游戏.由于大家c语言未学完,这个教程只涉及数组和函数等知识点. 蛇的身 ...