二叉树
是n(n>=0)个结点的有限集合,该集合或者为空集(称为空二叉树),或者由一个根结点和两棵互不相交的、分别称为根结点的左子树和右子树组成。
红黑树
二叉平衡树,当一边节点比另一边节点高,会自己做自平衡。不会出现单边递增的情况。数据多了,树高度会很高。
Hash表
- 查询快,但是不支持范围查询。hash冲突概率小。数据无序。
- 会对字段进行hash运算,直接查询到索引所在行磁盘文件地址。
B-Tree
- 叶节点具有相同的深度,叶节点的指针为空。
- 所有索引元素不重复。
- 节点中的数据索引从左到右递增排列。
- 非叶子节点存储data。
B+Tree
- 非叶子节点不存储data,只存储索引(冗余),可以放更多的索引。
- 叶子节点包含所有索引字段。
- 叶子节点用指针连接,提高区间访问的性能。
B+Tree将data放在叶子节点是因为一个节点只有16k,如果存放data数据,存储2000w的数据树的高度就会很高。树的高度越高,查询次数越多。
存储引擎形容的是数据库表(不管数据库定义何种存储引擎,最终以表为准)
MyISAM
-
索引文件和数据文件是分离的(非聚集)B+Tree组织
-
frm文件(建表信息),MYD文件(data数据),MYI文件(索引信息)
- 先去查询字段是否是索引字段,然后去MYI文件去查询当前字段的磁盘文件地址指针,然后再去MYD文件查询数据。
-
没有事务
Innodb
-
表数据文件本身就是按B+Tree组织的一个索引结构文件
-
聚集索引-叶节点包含了完整的数据记录
-
Innodb表必须有主键,并且推荐使用整形的自增主键
- 如果没有建主键,mysql会自己找一列可以建唯一索引的数据做主键。如果都找不到,则会生成一个隐藏列做主键。
- 整形比较大小快,并且存储空间小。
- 自增主键:永远往节点后面插入数据。不自增,则会在不同页插数据,效率会低(分库分表业务导致除外)
-
frm文件(建表信息),ibd文件(索引和data数据)
索引
-
聚集索引
主键,叶节点包含了完整的数据记录(索引和数据放在一个文件存储)
特点:查询数据特别快,因为聚集索引和行数据存储在磁盘的同一页,这样可以减少磁盘I/O操作次数
注意:主键索引应该尽量简短
-
非聚集索引(除了聚集索引以外的其它索引都叫非聚集索引)
- 叶子节点除了键值以外还包含了一个bookmark,用来告诉Innodb在哪里可以找到对应的行数据,Innodb的辅助索引的bookmark就说相对应行数据的聚集索引键。也就是先获取指向主键索引的主键,然后通过主键索引来找到一个完整的行。
- 不要在索引上用函数和like
- 非聚集索引里面存储了聚集索引,最后要通过聚集索引找到行数据。(聚集索引的效率会影像其他索引)
-
覆盖索引
索引包含了查询语句需要的所有数据。索引的叶子节点已经包含要查询的数据,不需要回表操作,所以很快。减少了I/O操作次数。
-
组合索引
把多个字段组合起来创建一个索引(最多16个字段),遵循最左前缀匹配原则。
-
最左前缀匹配原则
- mysql会从左向右匹配直到遇到不能使用索引的条件(>、<、!=、not 、like模糊查询的%前缀)才停止匹配。
- 如果a,b,c三个字段创建一个组合索引(a,b,c)。a是索引的最左前缀,所以where条件必须匹配字段a,mysql优化器才会用到这个索引。在匹配字段a的前提下,才能匹配字段b;在匹配字段a的前提下,并且匹配字段b,然后才能匹配字段c。
explain命令用来查看select语句执行计划,确认该sql语句有没有使用索引,是否做全表扫描,是否使用覆盖索引等。
type:代表数据访问类型(由左至右,由最差到最好)
| All | index | range | ref | eq_ref | const | system | null |
possible_keys: 表示那些索引可能有利于高效的查找
key:显示mysql决定采用哪个索引来优化查询
key_len:显示mysql在索引里使用的字节数
ref:显示了之前的表在key列记录的索引中查找值所用的列或常量
rows: 为了找到所需的行大致需要读取的行数
extra:表示额外的信息(左边较差,右边较好)
| Using filesort | Using temporary | Using where | Using index condition | Using index|
>>Using index:使用了覆盖索引,速度很快,限于查询字段都位于同一个索引中的场景。
>>Using index condition:表示使用了ICP优化(Index Condition Pushdown(索引下推)),能减少引擎层访问基表的次数和MySqlServer访问存储引擎的次数。
>>Using where:表示在存储引擎检索后mysql服务器再进行过滤
>>Using filesort:返回结果前需要做一次外部排序(内部或硬盘),速度慢应该尽量避免
>>Using temporary:在对查询结果排序时会使用一个临时表,速度慢
索引下推
-
先准备一张用户表(user),其中主要几个字段有:id、name、age、address。建立联合索引(name,age)。
name age id 张三 20 1 张一 21 2 李四 22 3
-
假设有一个需求,要求匹配姓名第一个为陈的所有用户,sql语句如下:
SELECT * from user where name like '张%'
-
根据 "最佳左前缀" 的原则,这里使用了联合索引(name,age)进行了查询,性能要比全表扫描肯定要高。
-
问题来了,如果有其他的条件呢?假设又有一个需求,要求匹配姓名第一个字为张,年龄为20岁的用户,此时的sql语句如下:
SELECT * from user where name like '张%' and age=20
-
Mysql5.6之前的版本是没有索引下推这个优化的,因此会忽略age这个字段,直接通过name进行查询,在(name,age)这颗树上查找到了多个结果id,然后拿着取到的id一次次的回表查询。
-
Mysql5.6之后Innodb没有忽略age这个字段,在索引内部就判断了age是否等于20,因此在(name,age)这颗树上查找到了一个结果id,只需回表一次。
-
索引下推在非主键索引上的优化,可以有效减少回表的次数。