标签:
本文翻译自Coding-Geek文章:《 How does a relational database work》。
原文链接:http://coding-geek.com/how-databases-work/#Buffer-Replacement_strategies
本文翻译了如下章节:
通过前面的章节, 我们已经理解了时间复杂和归并排序的概念,接下来我要介绍三种数据结构。这三种数据结构非常重要,它们是现代数据库系统的基础。我也会介绍数据库索引的概念。
二位数组是最简单的数据结构,一张数据库表就可以看成是一个二维数组。例如:
例如:你想找出在英国工作的所有人,你需要遍历每一行数据,判断他是否在英国。这个过程需要执行N步操作(N取决于数组的行数)。听起来,性能也不算太差,但有更快的方法吗?
肯定有,接下来就应该树结构登场了。
备注:现代数据库采用更高效的数组结构存储表数据,如heap-organized tables或者index-organized tables。但是都没有解决如何在数组中根据一些列的过滤条件快速筛选数据的问题。
这棵树有15个节点。我们看一下如何从中找到208这个元素:
接着看一下如何查找40这个元素:
最终,两次查询的操作步骤数都是树的高度。如果,你仔细阅读的merge sort章节,应该知道树的高度是log(N),所以该查找算法的时间复杂度是log(N)。还不错。
材料非常抽象,让我们回到问题上来。除了简单的整数型数据,考虑一下字符串,它是用于在前面的表中表示某个人的所属国家信息。假设,你已经构建了一个树,包含前面表中的“country”字段数据。
这个查询操作仅耗费了Log(N)步操作,而不是直接在数组中查询所需要的N步。现在你能猜到数据库索引是什么东西了吧?
你能为任意多列数据建立索引(一列字符串,一列整型数,2列字符串,一列整型 + 一列字符串,一列日期类型等等)。只要你对这些列实现了比较函数,你就能控制主键在树中的排列顺序(数据库已经为基本数据类型实现了比较函数)。
尽管上面的二叉树在查询某个固定值时工作得很好,但是如果要查询某个范围内的所有值,性能就非常低。它需要花费N步操作,因为需要比较树中的每一个节点以判断它是否在指定的范围内。此外,这种方式也很耗费I/O资源,因为要读取整个索引树。我们需要找到一种高效的范围查询方法(range query)。为解决这个问题,现代数据库使用B+树,B+树是前面二叉查询树的优化。在B+树里面:
其它节点的用途只在查询的时候,
在这个B+树里面,如果你查找40到100之前的数据:
假如,你需要查询M个节点,树有N个节点。查询指定的值(40)的时间复杂度是Log(N), 跟之前的二叉树查询一样。但是,一但你找到了节点(40),你还需要通过M步操作,遍历收集M个后继结点。B+的range query的时间复杂度是O(M+Log(N)), 相比之前二叉树O(N)复杂度,性能提升很多。数据量越大,性能差距越明显。你不需要读取整颗数据,这也意味着更小的磁盘I/O读取。
但是,这也带来了新的问题(再一次遇到问题)。如果你往数据库添加或者删除一行记录,同时也需要在B+树中更新数据:
换句话说,B+树必须要有自我调整树平衡性和节点顺序的能力。谢天谢地,智能化的数据删除和数据插入操作使得B+树的能保持以上特征。这也带来了成本:插入和删除数据的时间复杂度是O(Log(N)), 这也是为什么你经常会听到这样一种观点:索引太多不是什么好事。实际上,这会延缓插入/更新/删除操作的效率,因为数据库需要同时更新表的索引,每个索引花费O(Log(N))的时间。
译者注:凡是都有两面,有利必有裨;选择什么样的数据结构,是根据你的应用场景来的。
另外,索引也会增加tansaction manager的复杂(最后一张将讲到tansaction manager)。
更多的细节,你可以在维基百科上搜索B+ Tree。如果你想要一个B+树实现的样例,你可以读一下这篇文章(https://blog.jcole.us/2013/01/07/the-physical-structure-of-innodb-index-pages/), 这篇文章的作者是MySQL的核心开发人员。他详细讲述innoDB(MySQL数据库引擎)是如何实现索引的。
最后一个重要的数据结构是hash table。当你需要快速查找一个数据时,hash table非常有用。另外,理解了hash table将帮助我们理解后面将提到的一种常用数据库连接技术:hash join。Hash table也经常用于存储一些数据库的内部管理数据,如lock table,buff pool等。这些概念在后面都会讲到。
Hash table是一种能根据关键字快速查找数据的数据结构类型。构建hash table需要定义如下一些内容:
1) 元素关键字
2) 为关键字定义的哈希函数(hash function)。元素的关键字用哈希函数计算的结果表示了元素存储的位置(称为buckets)。
3) 关键字比较函数。一旦找到了元素所在的bucket,接下来需要在bucket内部,通过比较函数找到对应的值。
比较函数我使用判断两个整型数值是否相等的方法比较。
我们看一下如何找到hash table中找到元素78:
我们再看一下如何查找元素59:
如你所见,查询不同的值,时间复杂度是不同的。
如果你将哈希函数改为除以1000000取模(取数字的最后6位数,作为bucket标识)。上面的第二次查询只需要一步, 在bucket 59中没有任何数据。找一个好的哈希函数,保证每个bucket中存储尽可能少的数据,是非常困难的。
在上面的例子中找一个好的hash function非常容易。但这仅仅是一个简单的样例,如果关键字是如下数据类型,将非常困难:
1. 一个字符串(例如表示人的名)
2. 两个字符串(例如同时表示人的姓和名)
3. 两个字符串 + 一个日期(例如表示人的姓、名及生日)
设计一个好的hash function,哈希表的查询时间为O(1)。
为什么不使用数组? 问得好。
想了解更多的信息,你可以读一下介绍Java如何实现hash map的文章,它是hash map高效实现的一个样例。理解本文中概念,你不需要懂JAVA。
已翻译的《How does a relational database work》其它章节链接:
1. 关系型数据库工作原理-时间复杂度:http://blog.csdn.net/ylforever/article/details/51205332
2. 关系型数据库工作原理-归并排序:http://blog.csdn.net/ylforever/article/details/51216916
3. 关系型数据库工作原理-数据结构:http://blog.csdn.net/ylforever/article/details/51278954
4. 关系型数据库工作原理-高速缓存:http://blog.csdn.net/ylforever/article/details/50990121
5. 关系型数据库工作原理-事务管理(一):http://blog.csdn.net/ylforever/article/details/51048945
6. 关系型数据库工作原理-事务管理(二):http://blog.csdn.net/ylforever/article/details/51082294
关系型数据库工作原理-数据结构(翻译自Coding-Geek文章)
标签:
原文地址:http://blog.csdn.net/ylforever/article/details/51278954