【连载】关系型数据库是如何工作的?(4) - 数组、二叉搜索树

在我们理解了隐藏在时间复杂度和排序后面的思想之后,我必须再谈谈3种数据结构了。它们极其重要,因为它们是现代数据库的基石。我也会顺便介绍下索引的概念。

数组

二维数组是最简单的数据结构,一张数据库表就可以看做一个二维数组,例如:

二维数组就是一个既有行又有列的表:

  • 一行就表示一个主题(记录)
  • 一列就是描述主题(记录)的一个特性
  • 每一列存储同一个类型的数据(integer, string, date …)

虽然表能很好的存储并展示数据,但是当你需要搜索数据时,它的表现就很糟糕了。

例如,如果你要找到所有的英国朋友,你就必须查看每一行数据,然后判断他/她是否是英国人。这会耗用N个操作(N表示行的数量),虽然看起来也并没有多糟糕,可是让我们想想,有没有更好的方法呢?答案就是树。

注意,大部分现代数据库都会提供高级数组便于更高效的存储表,比如:基于堆、基于索引。但这样,也并没有解决在特定条件下快速搜索的难题。

树和数据库索引

一个二叉搜索树就是一个具有特定属性的二叉树,每个节点都满足下列属性:

  • 大于所有左侧子树的节点值
  • 小于所有右侧子树的节点值

让我们用图来更直观的说明二叉搜索树:

上图中的树包含15个节点,让我们来搜索值为208的节点:

  • 我从根节点136开始,发现126<208,因此我们查看根节点136右侧子树;
  • 398>208,因此继续查看398节点的左侧子树;
  • 250>208,因此继续查看250节点的左侧子树;
  • 200<208,因此继续查看200节点的左侧子树,但发现200节点没有左侧子树,因此说明值为208的节点不存在。

让我们换一个值来搜索,比如40:

  • 我从根节点136开始,发现136>40,因此我们查看根节点136左侧子树;
  • 80>40,因此继续查看80节点的左侧子树;
  • 40=40,节点存在。如果每个节点中包含了rowid,那么我们就可以查找表中指定的rowid;
  • 实际上,我们一旦知道rowid就可以精确的定位这一行数据在表中的位置,这样我就能立即获取这一行数据。

最终搜索耗费的操作就是树的高度。如果你认真的阅读了之前关于归并排序的章节,你应该能够推断实际操作数就是log(N),不错的效果咯!

回到问题

上边我们描述的都是节点值是整数的简单场景,那么如果我们的节点值不是整数怎么办呢?想想一下上表中的每个人的国籍,都是字符串类型。假设你有一个值为国籍的树:

  • 如果你想查找所有UK国籍的人;
  • 你可以查找树,找到值为UK的节点;
  • 在UK节点,然后你就可以在节点中获取国籍为UK的这一行的位置(rowid);

整个搜索过程耗费了log(N)次操作,而不是使用数组时的N次。上边的过程,实际就是通过数据库索引查找指定行的过程。

一旦拥有比较列值的函数,你就可以对任何类型的列进行排序,同时意味着你可以构造一棵索引树。(译者注:关键是能够比较列值,否则没法排序

下一章节我们继续介绍非常非常非常(译者注:重要的事情说三遍)重要的B+Tree索引。

时间: 2024-09-29 17:15:57

【连载】关系型数据库是如何工作的?(4) - 数组、二叉搜索树的相关文章

【连载】关系型数据库是如何工作的?(5) - B+Tree索引

虽然上一章节介绍的二叉搜索树在查询指定值时表现很好,但是当查询两个值之间的多个节点时,就会遇到很大的问题.因为需要遍历整个树的节点,并检查每个节点是否在指定的区间内.而且遍历整颗树是随机磁盘IO(译者注:随机IO会导致频繁的磁头换道,所以相比顺序IO来说非常耗时),所以我们需要找到一种更有效做范围查询的方法.为了解决这个难题,现代数据库修正了之前介绍的二叉搜索树,我们称修正后的数据结构为B+Tree: 只有叶子节点(树最底层的节点,图中橘黄色的节点)存储信息,即:行在表中精确的位置,也就是row

ORMBase对象/关系型数据库映射在MVC中的应用(二)

3.DataBase基类,查询方法返回值是List<T>,并且是分页的,ThePart.dll版本2.0中封装了一个PageInfo类,作为分页的类型.这种方法很机械,也很狗血..建议大家不这么用,下面这个例子是项目中同事写的.为了DataBase这个基类的操作数据库返回值各种类型,让人们知道各种情况的数据都可以处理.的这么一个目的,我还是把例子贴出来.我自己都难得去费神看. public static List<SportsBetRecords> SportsGetListPag

【连载】关系型数据库是如何工作的?(9) - 查询管理器

查询管理器 查询管理是一个数据库强大与否的一个判断指标.通过查询管理,可以把一个糟糕的查询语句转换为一段快速执行的代码,代码执行后返回结果给客户端管理器.整个过程分为多步: 查询首先被解析并检查其有效性: 重写查询并删除不必要的操作,另外做一些预优化: 为了提升性能进行必要的优化,最终转换为一个执行计划: 编译执行计划: 最后运行执行计划. 在读了这一章节之后,如果对查询优化想更深入的理解,我推荐阅读以下资料: 1979年发表的一篇最早的关于基于成本优化的论文:Access Path Selec

【连载】关系型数据库是如何工作的?(6) - Hash表

最后我们介绍的重要数据结构就是Hash表.当你需要快速查找的时候非常有用,而且理解Hash表会有助于我们以后理解常用数据库Join方式之一Hash join.这种数据结构常被数据库用作存储内部数据结构:表锁或缓存池(后续章节会介绍). Hash表能够通过元素Key快速找到元素的,为了构建一张Hash表,你需要定义: 一个元素的Key: 一个关于Key的Hash函数,Key的hash值就代表元素所在的位置(我们通常称为Hash桶): 一个关于Key的比较函数,一旦你找到了正确的桶,你就可以通过比较

【连载】关系型数据库是如何工作的?(7) - 数据库架构视图

现在我们可以看看数据库内部都有什么组件.一个数据库就是容易访问和修改的信息集合,实际上,一组简单的文件就可以做到.最简单的数据库SQLite就是由一组简单文件组成的,并且是一组精心设计的一组文件,它允许你: 通过事务保证数据的安全性和一致性: 即时海量数据也能保证快速处理数据. 通常,一个数据的组件视图如下: 在写下这部分内容之前,我阅读了很多书籍和论文,每一个都有其特有的方式来描述数据库.因此就不要纠结我怎么组织数据库,或者我怎么命名这些组件,因为我已经为此考虑良久来适合这篇文章.不同的组件并

【连载】关系型数据库是如何工作的?(11) - 查询管理器之重写

在重写这一步,我们拿到了查询SQL的内部表示,重写的目的是: 预优化SQL 避免不必要的操作 帮助优化器找到尽可能好的解决方案 重写器会在查询上匹配一系列规则,如果匹配一个规则就应用它重写查询,以下是部分可选的规则: 视图合并:如果你在查询中用了视图,那么视图就会被转换为一段代码: 优化子查询:由于一个子查询非常难以优化,因此重写器会修改子查询并删除子查询. 例如: SELECT PERSON.* FROM PERSON WHERE PERSON.person_key IN (SELECT MA

关系型数据库工作原理-事务管理(二)(翻译自Coding-Geek文章)

本文翻译自Coding-Geek文章:< How does a relational database work>. 原文链接:http://coding-geek.com/how-databases-work/#Buffer-Replacement_strategies 紧接上一篇文章,本文翻译了如下章节: 一. Log manager(日志管理) 通过前面的章节,我们已经知道,为了提升性能,数据库会将数据缓存在内存中.但是,如果在事务提交过程中,数据库服务器崩溃了.缓存在内存的数据就会丢失

关系型和非关系型数据库的区别--转载

关系型数据库和非关系型数据库 关系数据库和非关系数据库的区别是,关系数据库只有“表”这一种数据结构:而非关系数据库系统还有其他数据结构,对这些数据结构还有其他操作. 随着网络的不断发展,单纯关系数据库面临挑战. 关系与非关系型数据库的特点 1.关系型数据库 关系型数据库,是指采用了关系模型来组织数据的数据库. 简单来说,关系模型指的就是二维表格模型,而一个关系型数据库就是由二维表及其之间的联系所组成的一个数据组织. 关系模型中常用的概念: 关系:可以理解为一张二维表,每个关系都具有一个关系名,就

深入理解关系型数据库(一)

前言:是否写了很多年的SQL查询,仍然不知道这个大盒子里怎么运作的? 如果你感兴趣,不妨读读本文. 每当说到关系型数据库时,我总感觉少点什么.各式各样的数据库被到处使用,从轻量的SQLite到强大的Teradata.但是,几乎没有一篇文章来解释这些关系型数据库到底是怎样工作的.你使用谷歌搜索“关系型数据库的运行原理”,基本上搜不到什么结果.现在,如果你有接触到比较流行的技术(Big Data, NoSQL或者JavaScript),你却可以找到一些比较深入的介绍它们原理的文章. 难道关系型的数据