普通索引
由KEY或INDEX定义的索引,可以创建在任何数据类型,数据列可以有重复值,可以有null
唯一性索引
由UNIQUE定义的索引,数据列不允许重复,允许有null值
全文索引
由FULLTEXT定义的索引
InnoDB在MySQL5.6以后支持全文索引,只能创建在CHAR、VARCHAR或者TEXT类型字段的索引;MyISAM可以创建BLOB列的索引
空间索引
由SPATIAL定义的索引,只能创建在空间数据类型的字段上,共四种:GEOMETRY、POINT、LINESTRING、POLYGON。空间索引所在字段的值不能为空,表的存储引擎为MyISAM。
单列索引
只在一个字段上创建索引
多列索引
在多个字段上创建索引。多列索引中只有查询条件中使用了这些字段的第一个字段多列索引才会被使用。
主键索引
数据列不允许有重复值和null值,一个表只能有一个主键;
主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。
非主键索引
非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。
主键索引和非主键索引的区别
假设有如下的建表语句
mysql> create table T(
id int primary key,
k int not null,
name varchar(16),
index (k))engine=InnoDB;
即ID是主键索引,k是非主键索引。
select * from T where ID=500
,即主键查询方式,则只需要搜索 ID 这棵 B+ 树;* 如果语句是 select * from T where k=5
,即普通索引查询方式,则需要先搜索 k 索引树,得到 ID 的值为 500,再到 ID 索引树搜索一次。这个过程称为回表(回到主键索引树搜索)。也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询。
优点:新数据入库的时候,追加索引很快
缺点:做区间查询的时候比较慢,例如查找id在10-20之间的学生,就必须全部扫一遍
总结:适用于只有等值查询的场景,例如一些 NoSQL 引擎。
优点:
查询效率高,在等值查询和范围查询中性能都很好。等值查询直接二分法可以找,范围查询因为索引是有序的所以找起来也比较方便
缺点:
数据更新的时候比较麻烦,在数据中间插入数据就必须挪动后面的所有的元素,成本太高
总结:
适用于静态的存储引擎,例如要保存 2017 年某个城市的所有人口信息,这种一般不会修改的数据。
优点:
新数据入库的时候,加入索引比较快,查询效率比较快。
总结:各方面都比较折中,应用比较广泛。
InnoDB的索引模型是B+树。先介绍一下B树再介绍B+树。
B树
B树相比平衡二叉树来说更矮胖,从磁盘中查找数据(先读取到内存、后查找)的过程中,可以减少磁盘 IO 的次数,从而提升查找速度,常用于文件系统及数据库。
B树的特点:
B+树
优点:
B+ 树能够很好地配合磁盘的读写特性,减少单次查询的磁盘访问次数,同时访问起来比较稳定。
性能优化主要考虑避免全表扫描和有效地添加索引
1. 尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
如:select id from t where num is null
可以在num上设置默认值0,确保表中num列没有null值,然后这样查询:select id from t where num=0
2. 尽量避免在 where 子句中使用!=或<>操作符,否则引擎将放弃使用索引而进行全表扫描
3. 能用union all就避免使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描
例如select id from t where num=10 or num=20
可以这样查询:select id from t where num=10 union all select id from t where num=20
4. 能用between就不要用in和not in,否则会导致全表扫描
如:select id from t where num in(1,2,3)
对于连续的数值,可以修改为:select id from t where num between 1 and 3
5. 模糊查询例如select id from t where name like '李%'
也会导致全表扫描,尽可能使用全文索引
全文索引比 like + % 快 N 倍,但是可能存在精度问题。InnoDB 5.7.6之后才支持全文索引,MyISAM都支持全文索引。
MySQL 5.7.6之前只支持英文的全文索引;MySQL 5.7.6开始,MySQL内置了ngram全文解析器,用来支持中文、日文、韩文分词。
6. 任何地方都不要使用 select * from t
,用具体的字段列表代替“*”,不要返回用不到的任何字段
7. 用>=替代>
高效: SELECT * FROM EMP WHERE DEPTNO >=4
低效: SELECT * FROM EMP WHERE DEPTNO >3
两者的区别在于, 前者DBMS将直接跳到第一个DEPT等于4的记录,而后者将首先定位到DEPTNO=3的记录并且向前扫描到第一个DEPT大于3的记录。
参考