导语

索引在数据库中的地位是及其的重要,同时要想完全的掌握索引并不是一件容易的事,需要对数据的查询原理以及计算机操作系统有深刻的认识,当然相关的算法和数据结构也是必须的。因此,这篇文章感到了一些压力,不过还是决定先拿出来总结一下,理一理索引,就当做学习笔记了。

索引的重要习性犹如一本字典的拼音检索和部首检索部分,想象一下你买了一本只有正文的字典,那该有多么抓狂。而且在一个软件系统中,通常数据的查询与修改往往占到了10:1的比例,也就是我们需要将大部分的精力投入到数据的查询上,其中很多工作是用来提升查询的速度的,那么在这个过程中索引就扮演者非常重要的角色。

索引的实质

如果说一本字典的正文内容的实质是纸张的话,那么它前面按照拼音或者部首检索的索引的实质是什么呢!当然也是纸张了,可能有人觉得是废话,当我们同时类比到索引上就可以知道,一个数据表的实质是数据文件(即文件),那么索引的实质也当然是文件了,Mysql的InnoDB的数据表中的索引就是表空间的一部分。因此,初学者可以把索引完全想象成为一本字典,一本字典就是一个数据表,正文部分呢,就是这个数据表的详细内容,按照拼音和部首的检索都是索引。

当我们通过索引查找一条数据项的时候就犹如通过拼音索引查找某一个字,当在索引中查找到那个字的时候,会根据右边对应的页码找到那个字的解释,同样,MySQL的索引工作原理也是如此,每个索引项都有一个建索引列的关键字和一个指向该数据项的指针(类似字典中的页码),当我们查找到那个目标关键字时,根据指针便可以直接定位到数据表中该关键字的位置。

但现实中的真是数据表并不像字典那样,内容都是严格按照拼音序列排列的,因为有很多不确定的新内容要插入或者要进行其他操作,所以字典只是一种特殊的数据表,并不能把所有的数据表都拿来和字典比,这里用字典来类比只是为了对索引的实质有一个立体的认识。

索引是如何实现快速查找的

假设A公司有1024名员工(员工编号1-1024),早上的出勤人数为1023次,现在想知道员工编号为8的小明是否出勤,如何通过早上的签到表快速的查询小明是否出勤呢!在没有索引的情况下,通常的做法是从第一条记录逐个向后查找,如果小明最后一个来或者没有来,那么就需要查找1023次,效率为O(N)。也许会觉得1023次查找对现在的计算机根本不算什么,但是对于很多系统动辄都是上千万的数据记录,你可以想象查找的时间,比如你用15分钟终于通过了qq的身份校验登陆上了qq是一种怎么样的体验。因此,索引就呼之欲出了,我们如何通过索引来提高一个数量级的查找效率,这个时候就需要对这1024条数据做些什么了,在每条记录插入的时候,可以根据每条记录的员工编号和存储该记录的地址(指针)建立一个二叉查找树,这样1023条记录便可以通过10次查找便可查到,查找效率足足提高了100倍。

同样,为了效率的提升,也付出了一些代价,因为建立二叉查找树需要额外的存储空间,同时每次插入数据的时候需要对二叉查找树进行维护,减缓了数据的更新速度。但综合来考虑,一般认为这样做是值得的。

当然在MySQL中,不是采用的二叉树查找树来完成索引的存储的,上面举得例子只是为了说明索引的工作过程,但其思想是相同的。MySQL中没有特殊说明的话,一般说的索引指的就是B-Tree索引,采用B-Tree这种数据结构是综合了计算机操作系统以及组成而综合考虑的。其核心思想主要是减少磁盘的IO次数,提高查询速度。

如何理解聚簇索引

你只需记住它的名字叫聚簇索引,它不同于其他普通的索引!聚簇索引不仅仅是一种索引,更是一种存储方式,InnoDB中将B-Tree索引和数据行存储在一个数据结构中,意味着什么呢?这意味着数据行即索引,索引即数据行,它们是在一起,在一起,在一起的。

接着通过来建立字典的例子来理解聚簇索引和其他普通索引的区别,现在要建立一本中华字典,这个时候字典是空的,要我们造一本字典出来,首先我们要完成字典的正文,我们按照汉语拼音的顺序去组织字典的正文,第一个是“安 an ”,放在一个位置,同时后面附加上注释(这里,“an”就相当于聚簇索引的关键字,而后面的注释就是数据行,它们存在一起),第二个是“王 wang”字,通过和“安 an”字比较,拼音顺序靠后,所以放第二个。注意这里的放是指存储在磁盘中的位置,可以理解为存储顺序。第三个字是“小 xiao”字,通过拼音顺序,需要将第三个字存在第一个字“安”后面,那“王”字已经占了磁盘页面的位置,所以它需要向后面移动,如果移出该列,就导致了也分裂,所以可以看到聚集索引的更新代价真的很大,那为什么还要这样做呢?聚簇索引带来了那些好处?

......,假设按照上面方法已经建立好了字典的正文内容,这个时候就可以让我们体会一下聚簇索引的好处了,假如你要找“安 an”字,根据拼音序列,你一定知道它一定在前几个页面,所以直接可以翻到前面,同时你也可以找到拼音“an”所对应的所有的汉字,这就是聚簇索引带来的好处,同时聚簇索引是和数据行放在一起的,你不需要在根据索引里的指针找到对应的数据行,然后翻页找到(翻页就相当于磁盘IO),这些都是效率的提升。然而,上面也看到了聚簇索引的负面影响比如插入的时候,因此它就像一般利剑,用的合适效率提升,用的糟糕也会带来很大的不好影响。

是时候区别一下非聚聚索引了,这个时候我们又按照部首建立了一个索引,那么按照部首建立的索引就是非聚簇索引,它单独的存在在字典的前几个页面,而且同一个部首的字所对应的页码也是没有顺序的,如果我们要山字旁所对应的所有汉字,那就要取很多个页面的值,导致很多随机IO产生,同时不能很好利用计算机存储系统的缓存系统,因此效率远没有聚簇索引高。

InnoDB中聚簇索引产生的原则:

  • 当有主键时,主键为聚簇索引
  • 当没有主键时,引擎会选择一个唯一非空列来作为聚簇索引
  • 如果没有以上两种情况的列,引擎会隐式的定义一个主键作为聚簇索引

最后,通过建立一个数据表来感受聚簇索引,首先建立有一个没有主键也没有唯一非空列索引的数据表,即聚簇索引是系统隐式生成这种情况。这种情况,一般就是按数据插入的先后顺序进行排列。

CREATE TABLE user_log (
user_id INT NOT NULL,
place VARCHAR(20) NOT NULL DEFAULT '',
login_time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) DEFAULT CHARSET utf8;

接下来插入三条数据:

> INSERT INTO user_log(user_id,place)
VALUES('1','中国');
> INSERT INTO user_log(user_id,place)
VALUES('2','中国');
> INSERT INTO user_log(user_id,place)
VALUES('1','美国');

然后,选择所有列(即按照存储顺序查看数据列),果然如我们猜想,是按照插入顺序存储的:

>   SELECT * FROM user_log;

user_id	place	login_time
1 中国 2015-11-20 10:32:41
2 中国 2015-11-20 10:33:18
1 美国 2015-11-20 10:33:18

接下来,我们添加一个唯一的索引(ID+login_time),此时 系统引擎应该将此索引作为聚簇索引,因此我们再次插入新的数据的时候是按照ID聚簇存储的,就是说ID相同的会存储在一起,存储在同一个页面,甚至连续的几个页面。

下面首先添加这个唯一索引 并接着添加三条新的记录:

> ALTER TABLE user_log ADD UNIQUE KEY U_USER_LOG_ID_LOGIN_TIME(user_id,login_time);

> INSERT INTO user_log(user_id,place)
VALUES('1','法国');
> INSERT INTO user_log(user_id,place)
VALUES('2','日本');
> INSERT INTO user_log(user_id,place)
VALUES('1','韩国');

然后接着查看数据的存储情况:

>   SELECT * FROM user_log;

user_id	place	login_time
1 中国 2015-11-20 10:32:41
1 美国 2015-11-20 10:33:18
1 法国 2015-11-20 10:48:00
2 中国 2015-11-20 10:33:18
2 日本 2015-11-20 10:48:00

这样以来,如果我们要获取某一个用户的登陆情况,就可以非常的方便,因为该用户的所有登陆记录是按照ID聚集的存储在一起的,这样主存缓存一个页面的数据可能就OK了,如果是非聚集存储的,假如某个id的数据分散在100个页面,那么主存就要缓存这100个页面,效率可想而知。

总结

这篇文中一开始的构想是想从计算机操作系统的存储系统和B-Tree入手写的,结果写着写着发现,有点不太现实,一来文章长度可能增加几倍,二来可能自己都写晕了,既然是小白篇嘛,就先来个综述吧!总之索引是非常强大而且有意思的,然而当数据量达到一定量时,感觉索引也是有点乏力,但是尽量用好每一个索引是非常有必要而且是一种态度。

小白学习mysql之索引初步的更多相关文章

  1. 小白学习mysql之优化基础(EXPLAIN的连接类型)

    ## 导语很多情况下,有很多人用各种select语句查询到了他们想要的数据后,往往便以为工作圆满结束了.这些事情往往发生在一些学生亦或刚入职场但之前又没有很好数据库基础的小白身上,但所谓闻道有先后,只 ...

  2. Database学习 - mysql 数据库 索引

    索引 索引在mysql 中也叫 '键',是存储引擎用来快速找到记录的一种数据结构.索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈发重要. 索引优化应该是对查询性能优化 ...

  3. 小白学习mysql 之 innodb locks

    Innodb 锁类型: Shared and Exclusive Locks Intention Locks Record Locks Gap Locks Next-Key Locks Insert ...

  4. 小白学习mysql之存储过程的优劣分析以及接入控制

    存储过程的优劣 存储过程是一组实现特定功能的SQL语句集合,存储过程一经编译便存储在了服务器上,可以通过调用存储过程的名字以及传入相应的参数来使用存储过程.要高层次的掌握存储过程,不能觉得依葫芦画瓢, ...

  5. 小白学习mysql之函数

    ## 导语 曾经我以为,学会了select.update.insert和delete之后,我就学会了数据库~,要不是到公司看到SQL里充满了密密麻麻的的各种函数,我差点就信了~,当初的自己是多么的天真 ...

  6. STL 小白学习(1) 初步认识

    #include <iostream> using namespace std; #include <vector> //动态数组 #include <algorithm ...

  7. 【原创】MySQL(Innodb)索引的原理

    引言 回想四年前,我在学习mysql的索引这块的时候,老师在讲索引的时候,是像下面这么说的 索引就像一本书的目录.而当用户通过索引查找数据时,就好比用户通过目录查询某章节的某个知识点.这样就帮助用户有 ...

  8. MySQL(Innodb)索引的原理

    引言 回想四年前,我在学习mysql的索引这块的时候,老师在讲索引的时候,是像下面这么说的 索引就像一本书的目录.而当用户通过索引查找数据时,就好比用户通过目录查询某章节的某个知识点.这样就帮助用户有 ...

  9. 重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化

    重新学习MySQL数据库5:根据MySQL索引原理进行分析与优化 一:Mysql原理与慢查询 MySQL凭借着出色的性能.低廉的成本.丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库.虽然性能 ...

随机推荐

  1. Buffer篇

    // var buf1 = new Buffer(26);/*返回一个新的buffer对象,这个新buffer和老buffer公用一个内存.但是被start和end索引偏移缩减了.(比如,一个buff ...

  2. Linux运维工程师入门须掌握的10个技术点

    本人是linux运维工程师,对这方面有点心得,现在我说说要掌握哪方面的工具吧 说到工具,在行外可以说是技能,在行内我们一般称为工具,就是运维必须要掌握的工具. 我就大概列出这几方面,这样入门就基本没问 ...

  3. Python 基本类型转换

    python 有关字符串处理有哪些好用的方法?reverse len 字符串分割,合并?截取?查找? find index join split unicode字符串的表示 ""& ...

  4. python Quicksort demo

    __author__ = 'student' ''' quicksort step 1, choose one pivot, such as pivot=la[0] step 2, scan the ...

  5. TFS 2013”无法移除仍为团队管理员身份的标识”

    由于开发人员的工作变动,在TFS 2013的日常维护中,经常需要将已经离开团队的成员账户移除出本团队项目. 一.将用户从团队成员中移除 一般情况下,只需要在团队项目的控制面板界面(控制面板>Co ...

  6. linux -- read(), write()

    read()函数 2011-03-23 16:28:37|  分类: linux |  标签: |字号大中小 订阅     read函数从打开的设备或文件中读取数据. #include <uni ...

  7. 2014 Super Training #9 E Destroy --树的直径+树形DP

    原题: ZOJ 3684 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3684 题意: 给你一棵树,树的根是树的中心(到其 ...

  8. 2014 Super Training #10 D 花生的序列 --DP

    原题: FZU 2170 http://acm.fzu.edu.cn/problem.php?pid=2170 这题确实是当时没读懂题目,连样例都没想通,所以没做了,所以还是感觉这样散漫的做不好,有些 ...

  9. [cb] Assetbundle打包(一)

    一.简介 Unity的Assetbundle是Unity Pro提供的功能. 理解:Asset 资源,资产:Bundle :包,一批,捆:字面上的意思,就是把资源打包. 在项目中怎么使用Assetbu ...

  10. java 8-5 抽象

    1. 抽象类的概述: 动物不应该定义为具体的东西,而且动物中的吃,睡等也不应该是具体的. 我们把一个不是具体的功能称为抽象的功能,而一个类中如果有抽象的功能,该类必须是抽象类. 抽象类的特点: A:抽 ...