索引是在存储引擎中实现的,不同的存储引擎会使用不同的索引。
- MyISAM 和 InnoDB 只支持BTree索引
- MEMORY 和 HEAP 支持hash索引和Btree索引
索引分为四类
- 单列索引(普通索引,唯一索引,主键索引)
普通索引:没什么限制,允许插入空值和重复值
唯一索引:不允许重复值,允许空值
主键索引:不允许空值,不允许重复值 - 组合索引(联合索引)
遵循最左前缀原则
eg:(a,b,c)创建索引,共有(a),(a,b),(a,b,c)三种索引 - 全文索引
InnoDB,MyISAM引擎都能用,只能在CHAR,VARCHAR,TEXT类型的字段上加该索引。主要用来查找文本中的关键字,而不是直接与字段值进行比较,全文索引需要配合match against使用,而不是一般的where like… - 空间索引
是对空间数据类型的字段建立的索引,空间索引的列必须是not null,只有MyISAM支持该索引
索引在MySQL中的分类
- B+树索引
- Hash索引
- 全文索引
B树
因为内存的易失性,一般情况下,都会将表中的数据和索引存储在磁盘这种外围设备中,但是和内存相比,从磁盘中读取数据的速度会慢上千倍,从磁盘中读取数据都是按照磁盘块来读,并不是一条一条的读。
如果能尽量的把更多的数据放进磁盘里,那么一次读取就能获取更多数据,但是二叉树每个节点就存储一个键值对,如果用这种结构存储,那么每次读取一个键盘只能读到一个键值对,如果存储海量数据,占用磁盘过多,效率过慢。
为了解决这个弊端,创建了B树,B树是一个节点可以存储多个键值对的平衡树。
图中每个节点称为页,也就是磁盘块,在MySQL中读取的基本单位都是页。
假如要查找id=9 的数据:
1、先找到根节点,发现9小于17,根据指针P1,找到页2
2、将9和页2中的数据进行标胶发现9在8和12之间,根据P2找到页6
3、将9和页6中的键值进行比较,找到(9,ac)
B+树
B+树 和 B树的区别
1、B+树非叶子节点是不存储数据的,仅存储键值,因为数据库中页的大小是固定的,InnoDB默认是16k,如果不存储数据,就会存储更多的键值,另外,B+树的阶数等于键值的数量,如果B+树的一个节点可以存储1000个键值,那么三层的B+树可以存储100010001000 = 10亿个数据。
一般节点是常驻内存的,所以一般查找10亿数据只需要两次IO。
2、B+树的所有数据都存储在叶子节点,而且数据时按照顺序排列的,这就使得B+树的范围查找,排序查找,分组查找,以及去重查找变得简单。
B+树各个页之间通过双向链表连接的,叶子节点之间数据通过单向链表连接的,通过这些连接可以找到表中所有数据。
聚集索引和非聚集索引
-
聚集索引:
以InnoDB作为存储引擎的表,即使你不创建主键,系统也会帮你创建一个隐式的主键。因为InnoDB把数据存放在B+树中,而B+树的键值就是主键。这种以主键作为键值而构建的B+树索引称为聚集索引。 -
非聚集索引:
以主键之外的列值作为键值构建的B+树索引。与聚集索引的区别在于,叶子节点不存储表中的数据,而是存储该列对应的主键,想要查询数据还需要根据主键再去聚集索引中查找,称之为回表
叶子节点存储结构:
非聚集索引不一定进行回表操作,如果查询的字段全部命中了索引,就不必进行回表操作。
eg:select age from user where age<20
在索引上已经包含了age信息,不需要回表查询。
Hash索引
利用哈希函数h(k)计算出元素的位置
Hash索引的检索效率很高,索引的减速偶可以一次定位,不像B树索引需要从根节点到枝节点经过多次IO。
Hash索引缺点:
1、Hash只支持等值比较查询,如 = ,IN,<=>。不支持任何范围查询,因为Hash索引比较的值是经过hash运算之后的值,这些值的大小并不能保证和Hash运算之前完全一样。
2、Hash也无法进行排序操作,原因同上。
3、Hash索引在任何时候都不能避免表扫描,由于不同索引键存在相同hash值,所以即使满足某个hash值,也无法完成直接查询,而是要访问表中的数据进行比较。
4.不支持联合索引最左匹配原则。
MySQL中InnoDB和MyISAM的区别
- InnoDB支持事务,MyISAM不支持
- InnoDB支持外检,MyISAM不支持
- InnoDB是聚集索引,MyISAM是非聚集索引
- InnoDB不支持全文索引,MyISAM支持
MySQL中存在索引但是不被使用的情况
1、用“or”分隔开的两个条件,如果有一个条件没有索引,则不会使用索引
2、如果like以“%”开头,则不会使用索引
3、如果列类型为字符串,则where条件中该常量值必须加引号,否则索引不起作用
4、对索引列进行数学运算或者函数,索引不起作用
eg:select * from … where id-1=9
select * from … round(id) = 10