深入浅出数据库索引原理

前段时间,公司一个新上线的网站出现页面响应速度缓慢的问题, 一位负责这个项目的但并不是搞技术的妹子找到我,让我想办法提升网站的访问速度 ,因为已经有很多用户来投诉了。我第一反应觉的是数据库上的问题,假装思索了一下,摆着一副深沉炫酷的模样说:“是不是数据库查询上出问题了, 给表加上索引吧”,然后妹子来了一句:“现在我们网站访问量太大,加索引有可能导致写入数据时性能下降,影响用户使用的”。当时我就楞了一下, 有种强行装逼被拆穿的感觉,在自己的专业领域居然被非专业的同学教育, 面子上真有点挂不住。

其实, 我说这个例子并不是为展现我们公司的同事们专业能力的强大、做的产品棒、安全性高、性能牛逼, 连非技术的同事也懂得技术上的细节。事实上我只是想说明,「数据库」和「数据库索引」这两个东西是在服务器端开发领域应用最为广泛的两个概念,熟练使用数据库和数据库索引是开发人员在行业内生存的必备技能,而整天和技术人员打交道的非技术人员们,由于耳濡目染久了,自然也就能讲个头头是道了。

使用索引很简单,只要能写创建表的语句,就肯定能写创建索引的语句,要知道这个世界上是不存在不会创建表的服务器端程序员的。然而, 会使用索引是一回事, 而深入理解索引原理又能恰到好处使用索引又是另一回事,这完全是两个天差地别的境界(我自己也还没有达到这层境界)。很大一部份程序员对索引的了解仅限于到“加索引能使查询变快”这个概念为止。

  • 为什么要给表加上主键?

  • 为什么加索引后会使查询变快?

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

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

这些问题他们可能不一定能说出答案。知道这些问题的答案有什么好处呢?如果开发的应用使用的数据库表中只有1万条数据,那么了解与不了解真的没有差别, 然而, 如果开发的应用有几百上千万甚至亿级别的数据,那么不深入了解索引的原理, 写出来程序就根本跑不动,就好比如果给货车装个轿车的引擎,这货车还能拉的动货吗?

接下来就讲解一下上面提出的几个问题,希望对阅读者有帮助。

网上很多讲解索引的文章对索引的描述是这样的「索引就像书的目录, 通过书的目录就准确的定位到了书籍具体的内容」,这句话描述的非常正确, 但就像脱了裤子放屁,说了跟没说一样,通过目录查找书的内容自然是要比一页一页的翻书找来的快,同样使用的索引的人难到会不知道,通过索引定位到数据比直接一条一条的查询来的快,不然他们为什么要建索引。

想要理解索引原理必须清楚一种数据结构「平衡树」(非二叉),也就是b tree或者 b+ tree,重要的事情说三遍:“平衡树,平衡树,平衡树”。当然, 有的数据库也使用哈希桶作用索引的数据结构 , 然而, 主流的RDBMS都是把平衡树当做数据表默认的索引数据结构的。

我们平时建表的时候都会为表加上主键, 在某些关系数据库中, 如果建表时不指定主键,数据库会拒绝建表的语句执行。 事实上, 一个加了主键的表,并不能被称之为「表」。一个没加主键的表,它的数据无序的放置在磁盘存储器上,一行一行的排列的很整齐, 跟我认知中的「表」很接近。如果给表上了主键,那么表在磁盘上的存储结构就由整齐排列的结构转变成了树状结构,也就是上面说的「平衡树」结构,换句话说,就是整个表就变成了一个索引。没错, 再说一遍, 整个表变成了一个索引,也就是所谓的「聚集索引」。 这就是为什么一个表只能有一个主键, 一个表只能有一个「聚集索引」,因为主键的作用就是把「表」的数据格式转换成「索引(平衡树)」的格式放置。

上图就是带有主键的表(聚集索引)的结构图。图画的不是很好, 将就着看。其中树的所有结点(底部除外)的数据都是由主键字段中的数据构成,也就是通常我们指定主键的id字段。最下面部分是真正表中的数据。 假如我们执行一个SQL语句:

select * from table where id = 1256;

首先根据索引定位到1256这个值所在的叶结点,然后再通过叶结点取到id等于1256的数据行。 这里不讲解平衡树的运行细节, 但是从上图能看出,树一共有三层, 从根节点至叶节点只需要经过三次查找就能得到结果。如下图

假如一张表有一亿条数据 ,需要查找其中某一条数据,按照常规逻辑, 一条一条的去匹配的话, 最坏的情况下需要匹配一亿次才能得到结果,用大O标记法就是O(n)最坏时间复杂度,这是无法接受的,而且这一亿条数据显然不能一次性读入内存供程序使用, 因此, 这一亿次匹配在不经缓存优化的情况下就是一亿次IO开销,以现在磁盘的IO能力和CPU的运算能力, 有可能需要几个月才能得出结果 。如果把这张表转换成平衡树结构(一棵非常茂盛和节点非常多的树),假设这棵树有10层,那么只需要10次IO开销就能查找到所需要的数据, 速度以指数级别提升,用大O标记法就是O(log n),n是记录总树,底数是树的分叉数,结果就是树的层次数。换言之,查找次数是以树的分叉数为底,记录总数的对数,用公式来表示就是

用程序来表示就是Math.Log(100000000,10),100000000是记录数,10是树的分叉数(真实环境下分叉数远不止10), 结果就是查找次数,这里的结果从亿降到了个位数。因此,利用索引会使数据库查询有惊人的性能提升。

然而, 事物都是有两面的, 索引能让数据库查询数据的速度上升, 而使写入数据的速度下降,原因很简单的, 因为平衡树这个结构必须一直维持在一个正确的状态, 增删改数据都会改变平衡树各节点中的索引数据内容,破坏树结构, 因此,在每次数据改变时, DBMS必须去重新梳理树(索引)的结构以确保它的正确,这会带来不小的性能开销,也就是为什么索引会给查询以外的操作带来副作用的原因。

讲完聚集索引 , 接下来聊一下非聚集索引, 也就是我们平时经常提起和使用的常规索引。

非聚集索引和聚集索引一样, 同样是采用平衡树作为索引的数据结构。索引树结构中各节点的值来自于表中的索引字段, 假如给user表的name字段加上索引 , 那么索引就是由name字段中的值构成,在数据改变时, DBMS需要一直维护索引结构的正确性。如果给表中多个字段加上索引 , 那么就会出现多个独立的索引结构,每个索引(非聚集索引)互相之间不存在关联。 如下图

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

非聚集索引和聚集索引的区别在于, 通过聚集索引可以查到需要查找的数据, 而通过非聚集索引可以查到记录对应的主键值 , 再使用主键的值通过聚集索引查找到需要的数据,如下图

不管以任何方式查询表, 最终都会利用主键通过聚集索引来定位到数据, 聚集索引(主键)是通往真实数据所在的唯一路径。

然而, 有一种例外可以不使用聚集索引就能查询出所需要的数据, 这种非主流的方法 称之为「覆盖索引」查询, 也就是平时所说的复合索引或者多字段索引查询。 文章上面的内容已经指出, 当为字段建立索引以后, 字段中的内容会被同步到索引之中, 如果为一个索引指定两个字段, 那么这个两个字段的内容都会被同步至索引之中。

先看下面这个SQL语句

//建立索引

create index index_birthday on user_info(birthday);

//查询生日在1991年11月1日出生用户的用户名

select user_name from user_info where birthday = '1991-11-1'

这句SQL语句的执行过程如下

首先,通过非聚集索引index_birthday查找birthday等于1991-11-1的所有记录的主键ID值

然后,通过得到的主键ID值执行聚集索引查找,找到主键ID值对就的真实数据(数据行)存储的位置

最后, 从得到的真实数据中取得user_name字段的值返回, 也就是取得最终的结果

我们把birthday字段上的索引改成双字段的覆盖索引

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的值返回即可。 通过这种覆盖索引直接查找的方式, 可以省略不使用覆盖索引查找的后面两个步骤, 大大的提高了查询性能,如下图

数据库索引的大致工作原理就是像文中所述, 然而细节方面可能会略有偏差,这但并不会对概念阐述的结果产生影响 。

最后, 推荐三本关系数据库方面的书籍, 文中所讲解的概念内容都是来自于此。

《SQL Server2005技术内幕之T-SQL查询》

这本书虽然是针对SQL Server写的, 但是里面的大部份内容同样适用于其它关系数据库,此书对查询编写的技巧和优化讲解的非常透彻。

《关系数据库系统概论》第四版

王珊和萨师煊写的那本, 是大学计算机教材, 讲的通俗易懂, 在国内计算机书图书出版领域质量是排的上号的。

《数据库系统概念》

这本书在数据库领域非常出名, 被称之为帆船书, 书中内容博大精深,非一朝一夕可参透的。

本文首发于微信公众号 「带你撸出一手好代码」,欢迎关注获取更多原创分享

原文地址:http://www.cnblogs.com/aspwebchh/p/6652855.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326210.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2017蓝桥杯省赛---java---A---2(9数算式)

题目描述 思路分析 全排列check 代码实现 package TEST;import java.util.HashSet; import java.util.Set;class Main{static int[] a { 1, 2, 3, 4, 5, 6, 7, 8, 9 };static int ans;public static void main(String[] args) {f(0);System.out.println(ans / 2);}// 全排列…

android volley 上传图片 和参数,Android使用Volley实现上传文件功能

一个项目中用到的使用Volley上传头像文件的例子,供大家参考,具体内容如下/*** Created by wangshihui on 2015/11/30.* 上传文件* url:.....method:post参数:file接口给的参数:file 就是表单的key&#xff…

vue-router 如何在当前路由下重新点击当前路由的router-link实现刷新

转载自 vue-router 如何在当前路由下重新点击当前路由的router-link实现刷新 代码&#xff1a; <router-link to"/home" click.native"flushCom">首页</router-link> export default {......methods:{flushCom:function(){//router是路由实…

PS文字工具

文字工具&#xff1a; 快捷键&#xff1a;T 一、点文本&#xff1a; 1.使用文字工具直接在图像窗口中单击后输入的文本。 2.横排文字&#xff1a;右击文字工具–》选择横排文字 3.字体&#xff1a;自己在计算机中 实际是一个个字体文件&#xff0c;常用的字体有黑体、宋体和楷体…

Xamarin的Kimono以及Google的Guetzli和Draco

Xamarin开源了用于编辑SkiaSharp对象的工具&#xff0c;而Google则推出了减少2D JPEG和3D图形大小的方案。 Xamarin是微软的子公司&#xff0c;开源了Kimono设计器&#xff0c;它是一个用来图形化编辑SkiaSharp对象的工具&#xff0c;这种对象随后可以转换为目标平台的编码。S…

2017蓝桥杯省赛---java---A---7(正则问题)

题目描述 考虑一种简单的正则表达式&#xff1a; 只由 x ( ) | 组成的正则表达式。 小明想求出这个正则表达式能接受的最长字符串的长度。 例如 ((xx|xxx)x|(x|xx))xx 能接受的最长字符串是&#xff1a; xxxxxx&#xff0c;长度是6。输入 ---- 一个由x()|组成的正则表达式。输…

HTML表单元素

表单一、表单的语法&#xff1a; 1.提交方式&#xff1a; get:不安全&#xff0c;地址栏里面有提交内容 post:相对安全&#xff0c;地址栏里面不显示提交的内容 2.提交按钮&#xff1a;submit 3.重置按钮&#xff1a;reset 4.input中常用的属性&#xff1a; 1)type&#xf…

android 设置视频音量大小,为cocos2d-x添加调节视频音量的功能(Android)

为cocos2d-x添加调节视频音量的功能(Android)。日常吐槽cocos。我想放广告的时候播放一些其他声音&#xff0c;这时候我希望视频先静音&#xff0c;但是不停止播放。等声音播放完&#xff0c;我再放视频声音。赫然发现&#xff0c;VideoPlayer 居然没这个接口。而且现在视频的播…

Mybatis简介与原理

转载自 Mybatis简介与原理 什么是Mybatis MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code&#xff0c;并且改名为MyBatis 。iBATIS一词来源于“internet”和“abatis”的组合&#xff0c;是一个基于Java的持久层框…

JavaWeb前端之AJAX的初步学习

l AJAX的优点&#xff1a; 1、 最大的一点是页面没有刷新&#xff0c;在页面内与服务器通讯&#xff0c;给用户的体验非常好。 2、 使用异步的方式与服务器通讯&#xff0c;不需要打断用户的操作&#xff0c;具有更加速度的响应能力。 3、 可以…

Visual Studio 2017通过SSH支持Git

在大多数开发人员的工具包中&#xff0c;Git的重要性在不断提升&#xff0c;说它是一项必备技能也不为过&#xff0c;所以对于任意一款现代化的IDE来说&#xff0c;能够使用Git多样化的功能都是其重要的组成部分。在Visual Studio 2017中&#xff0c;微软已经在其UI界面中扩展了…

HTML列表、表格和媒体元素

列表、表格和媒体元素 一、列表&#xff1a;信息资源的一种展示形式 二、列表的分类&#xff1a;有序列表1.例子&#xff1a;<ol><li>内容</li></ol>2.特性&#xff1a;有顺序&#xff0c;每个li都是块级元素默认的li前面有顺序标记无序列表1.例子&…

2018蓝桥杯省赛---java---A---1(分数)

题目描述 思路分析 方案一 等比数列&#xff0c;再进行约分 方案二 求和 约分&#xff1a;辗转相除法求最大公约数 package TEST;class Main{static int GCD(int x,int y){//求最大公约数if(y0){return x;}return GCD(y,x%y);//是x%y&#xff0c;不是x/y}public static vo…

Android微信分享之微信项目注册与申请

Android微信开发 第一步&#xff1a;在微信开放平台注册账号以及申请项目&#xff1a; 创建应用&#xff0c;一个账户最多可以创建10个项目&#xff0c;安装要求填写。 注意点&#xff1a;申请keystory的方法&#xff01;经过测试最简单的方法为&#xff1a; 1、运行进入控制…

SpringMVC+Spring4+Mybatis3集成,开发简单Web项目+源码下载

转载自 SpringMVCSpring4Mybatis3集成&#xff0c;开发简单Web项目源码下载 基本准备工作 1、安装JDK1.6以上版本&#xff0c;安装与配置 2、下载mybatis-3.2.0版&#xff1a;https://repo1.maven.org/maven2/org/mybatis/mybatis/ 3、下载mybatis-spring-1.2.1版&#x…

微软宣布12月15日关闭开源软件托管平台CodePlex

网易科技讯4月1日消息&#xff0c;据Venturebeat报道&#xff0c;微软今天宣布&#xff0c;将关闭开源软件托管平台CodePlex。微软2006年推出这项服务&#xff0c;并决定在今年12月15日将其关闭。 微软公司副总裁布莱恩哈里&#xff08;Brian Harry&#xff09;在博文中写道&am…

C语言 立方体随鼠标转动,HTML5鼠标控制的旋转的立方体

拖拽思路&#xff1a;先定义上下左右重合在一起的六个面的旋转和移动角度立方体效果 transform-style: preserve-3d;定义初始值 transform: perspective(800px) rotateY(-60deg) rotateX(30deg);其中js效果中初始值 var x 30; var y -60;就是初始定义的旋转角度#box{width: 2…

HTML5的基础

HTML5的基础 一、HTML&#xff1a;Hyper Text MarkUp Language(超文本标记语言)。 二、W3C&#xff1a;1.world wide web consortium(万维网联盟)&#xff0c;成立于1994年&#xff0c;WEB技术领域最权威和最具影响力的国际中立性技术标准机构。2.w3c标准包括&#xff1a;结构化…

2018蓝桥杯省赛---java---A--2-(星期一)

题目描述 思路分析 方案一 翻电脑日历得2000年12月31日是周日 方案二 package TEST;class Main{public static void main(String[] args) {int sum0;for (int i 1901; i < 2000; i) {//开始的那天是星期二if((i%4000)||(i%100!0&&i%40)){sum366;}else {sum36…

Mybatis与Hibernate的详细对比

转载自 Mybatis与Hibernate的详细对比 前言 这篇博文我们重点分析一下Mybatis与Hibernate的区别&#xff0c;当然在前面的博文中我们已经深入的研究了Mybatis和Hibernate的原理。 Mybatis 【持久化框架】Mybatis简介与原理【持久化框架】SpringMVCSpring4Mybatis3集成&…