转自http://blog.csdn.net/u010003835/article/details/51563348

这篇文章是介绍MySQL数据库中的索引是如何根据需求一步步演变最终成为B+树结构的以及针对B+树索引的查询,插入,删除,更新等操作的处理方法。Oracle和DB2数据库索引的实现基本上也是大同小异的。文章写得很通俗易懂,就转在这了。关于B+树和索引内部结构可以参考:《B 树、B- 树、B+ 树和B* 树》和《深入理解DB2索引(Index)》。

 

00 – 背景知识

- B-Tree & B+Tree

http://en.wikipedia.org/wiki/B%2B_tree
  http://en.wikipedia.org/wiki/B-tree

- 折半查找(Binary Search)

http://en.wikipedia.org/wiki/Binary_search_algorithm

- 数据库的性能问题

A. 磁盘IO性能非常低,严重的影响数据库系统的性能。
  B. 磁盘顺序读写比随机读写的性能高很多。

- 数据的基本存储结构

A. 磁盘空间被划分为许多大小相同的块(Block)或者页(Page).
  B. 一个表的这些数据块以链表的方式串联在一起。
  C. 数据是以行(Row)为单位一行一行的存放在磁盘上的块中,如图所示.
  D. 在访问数据时,一次从磁盘中读出或者写入至少一个完整的Block。

Fig. 1

01 – 数据基本操作的实现

基本操作包括:INSERT、UPDATE、DELETE、SELECT。

- SELECT

A. 定位数据
  B. 读出数据所在的块,对数据加工
  C. 返回数据给用户

- UPDATE、DELETE

A. 定位数据
  B. 读出数据所在的块,修改数据
  C. 写回磁盘

- INSERT

A. 定位数据要插入的页(如果数据需要排序)
  B. 读出要插入的数据页,插入数据.
  C. 写回磁盘

如何定位数据?
- 表扫描(Table Scan)

A. 从磁盘中依次读出所有的数据块,一行一行的进行数据匹配。
  B. 时间复杂度 是O(n), 如果所有的数据占用了100个块。尽管只查询一行数据,
     也需要读出所有100个块的数据。
  C. 需要大量的磁盘IO操作,极大的影响了数据定位的性能。

因为数据定位操作是所有数据操作必须的操作,数据定位操作的效率会直接影响所有的数据操作的效率。
因此我们开始思考,如何来减少磁盘的IO?
- 减少磁盘IO

A. 减少数据占用的磁盘空间
     压缩算法、优化数据存储结构
  B. 减少访问数据的总量
     读出或写入的数据中,有一部分是数据操作所必须的,这部分称作有效数据。剩余的
     部分则不是数据操作必须的数据,称为无效数据。例如,查询姓名是‘张三’的记录。
     那么这条记录是有效记录,其他记录则是无效记录。我们要努力减少无效数据的访问。

02 – 索引的产生

- 键(Key)

首先,我们发现在多数情况下,定位操作并不需要匹配整行数据。而是很规律的只匹配某一个
  或几个列的值。 例如,图中第1列就可以用来确定一条记录。这些用来确定一条数据的列,统 
  称为键(Key).

Fig. 2

- Dense Index

根据减少无效数据访问的原则,我们将键的值拿过来存放到独立的块中。并且为每一个键值添
  加一个指针, 指向原来的数据块。如图所示,

                            Fig. 3

这就是‘索引’的祖先Dense Index. 当进行定位操作时,不再进行表扫描。而是进行
  索引扫描(Index Scan),依次读出所有的索引块,进行键值的匹配。当找到匹配的键值后,
  根据该行的指针直接读取对应的数据块,进行操作。假设一个块中能存储100行数据,
  10,000,000行的数据需要100,000个块的存储空间。假设键值列(+指针)占用一行数据
  1/10的空间。那么大约需要10,000个块来存储Dense索引。因此我们用大约1/10的额外存储
  空间换来了大约全表扫描10倍的定位效率。

03 – 索引的进化

  在实际的应用中,这样的定位效率仍然不能满足需求。很多人可能已经想到了,通过排序和查找
  算法来减少IO的访问。因此我们开始尝试对Dense Index进行排序存储,并且期望利用排序查
  找算法来减少磁盘IO。

- 折半块查找

A. 对Dense Index排序
  B. 需要一个数组按顺序存储索引块地址。以块为单位,不存储所有的行的地址。
  C. 这个索引块地址数组,也要存储到磁盘上。将其单独存放在一个块链中,如下图所示。
  D. 折半查找的时间复杂度是O(log 2(N))。在上面的列子中,dense索引总共有10,000个块。假设1个块
     能存储2000个指针,需要5个块来存储这个数组。通过折半块查找,我们最多只需要读取
     5(数组块)+ 14(索引块log 2(10000))+1(数据块)=20个块。

                                                                Fig. 4

- Sparse Index

实现基于块的折半查找时发现,读出每个块后只需要和第一行的键值匹配,就可以决定下一个块
  的位置(方向)。 因此有效数据是每个块(最后一个块除外)的第一行的数据。还是根据减少无
  效数据IO的原则,将每一个块的第一行的数据单独拿出来,和索引数组的地址放到一起。这样就
  可以直接在这个数组上进行折半查找了。如下图所示,这个数组就进化成了Sparse Index

                                                        Fig. 5

因为Sparse Index和Dense Index的存储结构是相同的,所以占用的空间也相同。大约需
  要10个块来存储10000个Dense Index块的地址和首行键值。通过Sparse索引,仅需要读
  取10(Sparse块)+1(Dense块)+1(数据块)=12个块.

- 多层Sparse Index

因为Sparse Index本身是有序的,所以可以为Sparse Index再建sparse Index。通过
  这个方法,一层一层的建立 Sparse Indexes,直到最上层的Sparse Index只占用一个块
  为止,如下图所示.

                                       Fig. 6

A. 这个最上层的Sparse Index称作整个索引树的根(root).
  B. 每次进行定位操作时,都从根开始查找。
  C. 每层索引只需要读出一个块。
  D. 最底层的Dense Index或数据称作叶子(leaf).
  E. 每次查找都必须要搜索到叶子节点,才能定位到数据。
  F. 索引的层数称作索引树的高度(height).
  G. 索引的IO性能和索引树的高度密切相关。索引树越高,磁盘IO越多。

在我们的例子中的Sparse Index,只有10个块,因此我们只需要再建立一个Sparse Index.
  通过两层Sparse Index和一层Dense Index查找时,只需读取1+1+1+1=4个块。

- Dense Index和Sparse Index的区别

A. Dense Index包含所有数据的键值,但是Sparse Index仅包含部分键值。
     Sparse Index占用更少的磁盘空间。
  B. Dense Index指向的数据可以是无序的,但是Sparse Index的数据必须是有序的。
  C. Sparse Index 可以用来做索引的索引,但是Dense Index不可以。
  D. 在数据是有序的时候,Sparse Index更有效。因此Dense Index仅用于无序的数据。
  E. 索引扫描(Index Scan)实际上是对Dense Index层进行遍历。

- 簇索引(Clustered Index)和辅助索引(Secondary Index)

如果数据本身是基于某个Key来排序的,那么可以直接在数据上建立sparse索引,
  而不需要建立一个dense索引层(可以认为数据就是dense索引层)。 如下图所示:

                                                Fig. 7

这个索引就是我们常说的“Clustered Index”,而用来排序数据的键叫做主键Primary Key.

A. 一个表只能有一个Clustered Index,因为数据只能根据一个键排序.
  B. 用其他的键来建立索引树时,必须要先建立一个dense索引层,在dense索引层上对此键的值
     进行排序。这样的索引树称作Secondary Index.
  C. 一个表上可以有多个Secondary Index.
  D. 对簇索引进行遍历,实际上就是对数据进行遍历。因此簇索引的遍历效率比辅组索引低。
     如SELECT count(*) 操作,使用辅组索引遍历的效率更高。

- 范围搜索(Range Search)

由于键值是有序的,因此可以进行范围查找。只需要将数据块、Dense Index块分别以双向链表
  的方式进行连接, 就可以实现高效的范围查找。如下图所示:

0619数据库_MySQL_由浅入深理解索引的实现的更多相关文章

  1. MySQL 数据库性能优化之索引优化

    接着上一篇 MySQL 数据库性能优化之表结构,这是 MySQL数据库性能优化专题 系列的第三篇文章:MySQL 数据库性能优化之索引优化 大家都知道索引对于数据访问的性能有非常关键的作用,都知道索引 ...

  2. Elasticsearch-深入理解索引原理

    最近开始大面积使用ES,很多地方都是知其然不知其所以然,特地翻看了很多资料和大牛的文档,简单汇总一篇.内容多为摘抄,说是深入其实也是一点浅尝辄止的理解.希望大家领会精神. 首先学习要从官方开始地址如下 ...

  3. 【由浅入深理解java集合】(四)——集合 Queue

    今天我们来介绍下集合Queue中的几个重要的实现类.关于集合Queue中的内容就比较少了.主要是针对队列这种数据结构的使用来介绍Queue中的实现类. Queue用于模拟队列这种数据结构,队列通常是指 ...

  4. 【由浅入深理解java集合】(三)——集合 List

    第一篇文章中介绍了List集合的一些通用知识.本篇文章将集中介绍List集合相比Collection接口增加的一些重要功能以及List集合的两个重要子类ArrayList及LinkedList. 一. ...

  5. 【由浅入深理解java集合】(二)——集合 Set

    上一篇文章介绍了Set集合的通用知识.Set集合中包含了三个比较重要的实现类:HashSet.TreeSet和EnumSet.本篇文章将重点介绍这三个类. 一.HashSet类 HashSet简介 H ...

  6. 【由浅入深理解java集合】(一)——集合框架 Collction、Map

    本篇文章主要对java集合的框架进行介绍,使大家对java集合的整体框架有个了解.具体介绍了Collection接口,Map接口以及Collection接口的三个子接口Set,List,Queue. ...

  7. 由浅入深理解 IOC 和 DI

    目录 由浅入深理解 IOC 和 DI 开闭原则 OCP(Open Closed Principle) 面向抽象编程 逐步理解实现 IOC 和 DI 的过程(LOL Demo 示例) 比较尴尬的编写程序 ...

  8. 关于数据库表中的索引及索引列的CRUD

     -- 查询一个数据库表中的索引及索引列use [RuPengWangDB]GOSELECT  indexname = a.name , tablename = c. name , indexcolu ...

  9. Oracle数据库之视图与索引

    Oracle数据库之视图与索引 1. 视图简介 视图是基于一个表或多个表或视图的逻辑表,本身不包含数据,通过它可以对表里面的数据进行查询和修改. 视图基于的表称为基表,视图是存储在数据字典里的一条SE ...

随机推荐

  1. C# winform 组件---- folderBrowserDialog与openFileDialog(转)

    C# winform 组件---- folderBrowserDialog与openFileDialog 2009-06-27 13:36 2153人阅读 评论(1) 收藏 举报 winformc#b ...

  2. Codeforces--630B--Moore's Law(快速幂)

     Moore's Law Time Limit: 500MS   Memory Limit: 65536KB   64bit IO Format: %I64d & %I64u Submit ...

  3. B1218 [HNOI2003]激光炸弹 dp

    这个题其实打眼一看就知道差不多是dp,而且基本确定是前缀和.然后硬钢就行了...直接暴力预处理前缀和,然后直接dp就行. 题干: Description 一种新型的激光炸弹,可以摧毁一个边长为R的正方 ...

  4. 687C

    dp 以前做过 忘了. 想破脑袋不知道怎么设状态 dp[i][j][k]表示选到第i个硬币,当前和为j,能否弄出k dp[i][j][k]|=dp[i-1][j][k]|dp[i-1][j][k-c[ ...

  5. 76.培训记录信息 Extjs 页面

    1.培训记录信息页面jsp <%@ page language="java" import="java.util.*" pageEncoding=&quo ...

  6. 96.extjs 页面

    1.登录js /** * @author sux * @desc 登录 */ Ext.onReady(function(){ Ext.QuickTips.init(); //错误信息显示必须 var ...

  7. B. Sereja and Suffixes(cf)

    http://codeforces.com/problemset/problem/368/B B. Sereja and Suffixes time limit per test 1 second m ...

  8. javascript中执行环境和作用域(js高程)

    执行环境(execution context,为简单起见,有时也成为“环境”)是javascript中最为重要的一个概念.执行环境定义了变量或函数有权访问的其他数据,决定了它们各自的行为.每个执行环境 ...

  9. SQL SERVER 2000 如何提高大数据筛选GROUP BY 的效率

    数据库有83W条记录,本想计算20180101之后的每天赔付情况,故写了以下SQL语句: SELECT 起保时间,sum(赔付金额) as 日赔付 FROM maindata WHERE 起保时间&g ...

  10. hibernate_05_单表操作_对象类型

    本篇使用hibernate输出一个对象(图片) 先写一个java类 package com.imooc.hibernate; import java.sql.Blob; import java.uti ...