维基百科对数据库索引的解释:一个排序的数据结构,以协助快速查询、更新数据库表中数据。html
MySQL官方解释:索引(Index)是帮助MySQL高效获取数据的数据结构。mysql
综上所述,就能够获得索引的本质:索引(在MYSQL中也叫作键)是数据结构。算法
对于咱们平常使用的MySQL数据库来讲,它支持多种索引类型,如BTree索引,哈希索引,全文索引等等。然而我在大部分时候都会使用BTree索引,至于哈希索引和全文索引本文暂不讨论。sql
索引的目的在于提升查询效率,能够类比字典,若是要查“mysql”这个单词,咱们确定须要定位到m字母,而后从下往下找到y字母,再找到剩下的sql。若是没有索引,那么你可能须要把全部单词看一遍才能找到你想要的,若是我想找到m开头的单词呢?或者x开头的单词呢?是否是以为若是没有索引,这个事情根本没法完成?数据库
最简单的例子就是若是1000条数据,1到100分红第一段,101到200分红第二段,201到300分红第三段……这样查第250条数据,只要找第三段就能够了,一会儿去除了90%的无效数据。但若是是1千万的记录呢,分红几段比较好?稍有算法基础的同窗会想到搜索树,其平均复杂度是lgN,具备不错的查询性能。可是考虑到磁盘IO是很是高昂的操做,计算机操做系统作了一些优化,当一次IO时,不光把当前磁盘地址的数据,而是把相邻的数据也都读取到内存缓冲区内,由于局部预读性原理告诉咱们,当计算机访问一个地址的数据的时候,与其相邻的数据也会很快被访问到。每一次IO读取的数据咱们称之为一页(page)。具体一页有多大数据跟操做系统有关,通常为4k或8k,也就是咱们读取一页内的数据时候,实际上才发生了一次IO,因此为了提升性能,每次又能够把部分数据读入内存来计算,由于咱们知道访问磁盘的成本大概是访问内存的十万倍左右,这个理论对于索引的数据结构设计很是有帮助。数据结构
咱们如今总结一下,咱们须要这种数据结构可以作些什么,那就是:每次查找数据时把磁盘IO次数控制在一个很小的数量级,最好是常数数量级。那么咱们就想到若是一个高度可控的多路搜索树是否能知足需求呢?就这样,b+树应运而生。函数
维基百科:B+ 树是一种树数据结构,一般用于数据库和操做系统的文件系统中。B+ 树的特色是可以保持数据稳定有序,其插入与修改拥有较稳定的对数时间复杂度。B+ 树元素自底向上插入,这与二叉树刚好相反。性能
如上图,是一颗b+树,浅蓝色的块咱们称之为一个磁盘块,能够看到每一个磁盘块包含几个数据项(深蓝色所示)和指针(黄色所示),如磁盘块1包含数据项17和35,包含指针P一、P二、P3,P1表示小于17的磁盘块,P2表示在17和35之间的磁盘块,P3表示大于35的磁盘块。真实的数据存在于叶子节点即三、五、九、十、1三、1五、2八、2九、3六、60、7五、7九、90、99。非叶子节点只不存储真实的数据,只存储指引搜索方向的数据项,如1七、35并不真实存在于数据表中。大数据
如上图所示,若是要查找数据项29,那么首先会把磁盘块1由磁盘加载到内存,此时发生一次IO,在内存中用二分查找肯定29在17和35之间,锁定磁盘块1的P2指针,内存时间由于很是短(相比磁盘的IO)能够忽略不计,经过磁盘块1的P2指针的磁盘地址把磁盘块3由磁盘加载到内存,发生第二次IO,29在26和30之间,锁定磁盘块3的P2指针,经过指针加载磁盘块8到内存,发生第三次IO,同时内存中作二分查找找到29,结束查询,总计三次IO。真实的状况是,3层的b+树能够表示上百万的数据,若是上百万的数据查找只须要三次IO,性能提升将是巨大的,若是没有索引,每一个数据项都要发生一次IO,那么总共须要百万次的IO,显然成本很是很是高。优化
索引的优势咱们都知道就是为了提升查询效率,当时他也有本身的缺点。
当一个数据表的字段加了索引以后,加快了检索速度,可是他同时页下降了索引列的插入,更新,删除操做的速度,由于一个行不只是写入一个数据行,还要更改索引,表的索引越多,须要作的更改就越多,平均性能也就越低。
索引也会占用磁盘空间,大量的对表中字段加索引,有可能致使索引文件比数据文件更快的到达表的大小极限。
说白了这就是一种以空间换时间的作法,因此不要建立没有必要的索引。
1.用于搜索,排序,或者分组的列建立索引,而对于输出现实的列则不用于建立索引,也就是说,最佳索引候选列九十出如今where条件后面的列,链接子句后面的列,order by,group by后面的列。
2.认真考虑数据列基数,列的基数(carddinality)是指它所容纳全部非重复的数值的个数,区分度的公式是count(distinct col)/count(*),比例越大咱们扫描的记录数越少,惟一键的区分度是1,例如,某个列包含1,3,5,3,7,8,7,1,8,他的基数就是5,因此列的基数越高,也就是重复值越少,索引的使用效果越好。
3.索引短小值,例如当数据类型使用int就能存下你须要存储的数据时,就不要使用bigint。
(1)短小值可让比较操做更快,从而加快索引检索速度
(2)短小值可让索引更短更小,从而减小IO请求
(3)短小值可让磁盘往内存里加载更多的键值,那么就能够减小从磁盘读取数据而更多的直接从内存中读取
4.最左前缀匹配原则,很是重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)就中止匹配,好比a = 1 and b = 2 and c > 3 and d = 4 若是创建(a,b,c,d)顺序的索引,d是用不到索引的,若是创建(a,b,d,c)的索引则均可以用到,a,b,d的顺序能够任意调整,好比like (%as)就不走索引,而like(as%)就能够。
5.索引列不能参与计算,保持列“干净”,好比from_unixtime(create_time) = ’2019-12-16’就不能使用到索引,缘由很简单,b+树中存的都是数据表中的字段值,但进行检索时,须要把全部元素都应用函数才能比较,显然成本太大。因此语句应该写成create_time = unix_timestamp(’2014-05-29’),因此咱们知道了mysql中内置函数是不走索引的。
6.尽可能的扩展索引,不要新建索引,好比表中已经有a的索引,如今要加(a,b)的索引,那么只须要修改原来的索引便可。
关于explain命令相信你们并不陌生,具体用法和字段含义能够参考官网explain-output。
参考资料:
MySQL技术内幕-第5版
美团技术团队-MySQL索引原理及慢查询优化