【SQL】浅谈关系型数据库的索引原理

来源:https://zhuanlan.zhihu.com/p/23624390
作者:陈大侠

本文将解决四个问题:
为什么要给表加上主键?
为什么加索引之后会使查询变快?
为什么加索引后会使写入、修改、删除变慢?
什么情况下要同时在两个字段上建索引?

一、为什么要给表加上主键?

形象地说,如果我们建一个不加主键的表,那么它的记录是一行一行排列整齐地放置在磁盘存储器上的。它是真正的“表”结构。
另一方面,如果我们建一个加主键的表,那么表在磁盘上的存储结构就不是整齐排列的了,而是变成了树状结构,即“平衡树”结构。

  • 换句话说,就是整个表变成了一个索引,即所谓的聚集索引

1.平衡树
平衡树是指子树的高度差不超过1。
通俗地讲,就是每个叶子节点都均匀一些,不要太凸出。

2.聚集索引

  • 聚集索引依据键值的逻辑顺序来决定表中数据相应的物理顺序。

为什么一个表只能有一个聚集索引?

  • 因为一个表的物理顺序只有一种情况,因此一个表只能有一个聚集索引。

为什么一个表只能有一个主键?

  • 因为主键的作用就是把表的数据存储方式转化成聚集索引(平衡树)的存储方式,而聚集索引只有一种,因此一个表只能有一个主键。

3.一个例子

图片说明
上图就是一个带主键的表(聚集索引)的结构图。
其中树的所有节点(底部除外)的数据都是由主键字段中的数据构成。
假如我们执行一个SQL语句:

SELECT * FROM table WHERE id =1256;

图片说明
如上图,首先根据索引定位到1256这个值所在的叶节点,然后再通过叶节点渠道id等于1256的数据行。

二、为什么加索引之后会使查询变快?

表的存储格式变成树状结构之后,我们查询的次数就不再是记录的个数,而是平衡树的高度;平衡树的高度和记录的个数的关系是:
图片说明
这样,利用索引就会使数据库查询有惊人的性能提升。

证明:n个节点的二叉平衡树的高度是O(log2 n)。
图片说明

三、为什么加索引后会使写入、修改、删除变慢?

主要是为了维护平衡树这个结构。
增删改数据都会改变平衡树各节点中的索引数据内容,从而破坏树结构,因此,在每次数据改变时,DBMS必须去重新梳理树(索引)的结构以确保它的正确,这会带来不小的性能开销。

四、什么情况下要同时在两个字段上建索引?

让我们先看看非聚集索引,也就是我们平时经常使用的常规索引。

1.非聚集索引
非聚集索引同样采用平衡树作为索引的数据结构。索引树结构中各节点的值来自于表中的索引字段。

例如,假如给user表的name字段加上索引,那么索引就是由name字段中的值构成。在数据改变时,DBMS需要一直维护索引结构的正确性。

如果给表中多个字段加上索引,那么就会出现多个独立的索引结构,每个索引(非聚集索引)相互之间不存在关联。
图片说明

每次给字段建一个新索引,字段中的数据就会被复制一份出来,用于生成索引。因此,给表添加索引,会增加表的体积,占用磁盘存储空间。

非聚集索引和聚集索引的区别在于,通过聚集索引可以查到需要查找的数据,二通过非聚集索引可以查到记录对应的主键值,再使用主键的值通过聚集索引查找到需要的数据。
图片说明
不管以任何方式查询表,最终都会利用主键通过聚集索引来定位到数据,聚集索引(主键)是通往真实数据所在的唯一路径。

2.覆盖索引(复合索引、多字段索引)
这种非主流的索引方式,可以不使用聚集索引来查询数据。
上文指出,当字段建立索引以后,字段中的内容会被同步到索引之中;如果为一个索引指定两个字段,那么这两个字段的内容都会被同步到索引之中。

例,执行下面的SQL语句

CREATE INDEX index_birthday ON user_info(birthday); // 建立索引

SELECT user_name 
FROM user_info
WHERE birthday = '1991-11-1'; // 查询生日再1991年11月1日出生用户的用户名

这句查询SQL语句的执行过程如下:

  • 首先,通过非聚集索引index_birthday查找birthday等于1991-11-1的所有记录的主键ID值;
  • 然后,通过得到的主键ID值执行聚集查找,找到主键ID值对应的真实数据(数据行)存储的位置;
  • 最后,从得到的真实数据中取得user_name字段的值返回。

如果我们把birthday字段上的索引改成双字段的覆盖i索引:

CREATE INDEX index_birthday_and_user_name ON user_info(birthday, user_name); 

这句查询SQL语句的执行过程就变为:

  • 通过非聚集索引index_birthday_and_user_name查找birthday等于1991-11-1的叶节点内容;
  • 然而,叶结点中除了有user_name表主键ID的值外,user_name字段的值也在里面,因此不需要通过主键ID值得查找数据行的真实所在,直接取得叶节点中user_name的值返回即可。

通过这种覆盖索引直接查找的方式,可以省略不使用覆盖索引查找的后面两个步骤,大大提高查询性能。
图片说明

全部评论

相关推荐

06-27 12:54
已编辑
门头沟学院 Java
累了,讲讲我的大学经历吧,目前在家待业。我是一个二本院校软件工程专业。最开始选专业是觉得计算机感兴趣,所以选择了他。本人学习计算机是从大二暑假结束开始的,也就是大三开始。当时每天学习,我个人认为Java以及是我生活的一部分了,就这样持续学习了一年半,来到了大四上学期末,大概是在12月中旬,我终于找的到了一家上海中厂的实习,但我发现实习生的工作很枯燥,公司分配的活也不多,大多时间也是自己在自学。就这样我秋招末才找到实习。时间来到了3月中旬,公司说我可以转正,但是转正工资只有7000,不过很稳定,不加班,双休,因为要回学校参加答辩了,同时当时也是心高气傲,认为可以找到更好的,所以放弃了转正机会,回学校准备论文。准备论文期间就也没有投递简历。然后时间来到了5月中旬,这时春招基本也结束了,然后我开始投递简历,期间只是约到了几家下场面试。工资也只有6-7k,到现在我不知道该怎么办了。已经没有当初学习的心劲了,好累呀,但是又不知道该干什么去。在家就是打游戏,boss简历投一投。每天日重一次。26秋招都说是针对26届的人,25怎么办。我好绝望。要不要参加考公、考研、央国企这些的。有没有大佬可以帮帮我。为什么感觉别人找工作都是顺其自然的事情,我感觉自己每一步都在艰难追赶。八股文背了又忘背了又忘,我每次都花很长时间去理解他,可是现在感觉八股、项目都忘完了。真的已经没有力气再去学习了。图片是我的简历,有没有大哥可以指正一下,或者说我应该走哪条路,有点不想在找工作了。
码客明:太累了就休息一下兄弟,人生不会完蛋的
如果实习可以转正,你会不...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务