1. 索引
MySQL官方对索引定义:是存储引擎用于快速查找记录的一种数据结构。需要额外开辟空间和数据维护工作索引是物理数据页存储,在数据文件中(InnoDB,ibd文件),利用数据页(page)存储
索引可以加快检索速度,但是同时也会降低增删改操作速度,索引维护需要代价
1.1 普通索引
是最基本的索引类型,基于普通字段建立的索引,没有任何限制
1.2 唯一索引
与"普通索引"类似,不同的就是:索引字段的值必须唯一,但允许有空值 。在创建或修改表时追加唯一约束,就会自动创建对应的唯一索引
1.3 主键索引
它是一种特殊的唯一索引,不允许有空值。在创建或修改表时追加主键约束即可,每个表只能有一个主键
1.4 复合索引
用户可以在多个列上建立索引,这种索引叫做组复合索引(组合索引)
复合索引可以代替多个单一索引,相比多个单一索引,复合索引所需的开销更小窄索引
窄索引是指索引列为1-2列的索引
宽索引
索引列超过2列的索引
设计索引的一个重要原则就是能用窄索引不用宽索引,因为窄索引往往比组合索引更有效复合索引使用注意事项:
(1)何时使用复合索引,要根据where条件建索引,注意不要过多使用索引,过多使用会对更新操作效率有很大影响
(2)如果表已经建立了(col1,col2),就没有必要再单独建立(col1);
(3)如果现在有(col1)索引,如果查询需要col1和col2条件,可以建立(col1,col2)复合索引,对于查询有一定提高
1.5 全文索引
查询操作在数据量比较少时,可以使用like模糊查询,但是对于大量的文本数据检索,效率很低。如果使用全文索引,查询速度会比like快很多倍。但也很少用到。
在MySQL 5.6 以前的版本,只有MyISAM存储引擎支持全文索引,从MySQL 5.6开始MyISAM和InnoDB存储引擎均支持创建索引
CREATE FULLTEXT INDEX ON tablename (字段名);
使用索引
select * from user where match(name) against('aaa');
2. 索引原理
索引涉及的理论知识:二分查找法、Hash和B+Tree
2.1 索引数据结构
MySQL数据库索引采用的是B+Tree结构,在B-Tree结构上做了优化改造
B+Tree结构非叶子节点不存储data数据,只存储索引值,这样便于存储更多的索引值
叶子节点包含了所有的索引值和data数据
叶子节点用指针连接,提高区间的访问性能
B+树进行范围查找时,只需要查找定位两个节点的索引值,然后利用叶子节点的指针进行遍历即可聚簇索引和非聚簇索引
B+Tree的叶子节点存放主键索引值和行记录就属于聚簇索引;如果索引值和行记录分开存放就属于非聚簇索引
主键索引和辅助索引
B+Tree的叶子节点存放的是主键字段值就属于主键索引;如果存放的是非主键值就属于辅助索引(二级索引)
2.2 聚簇索引
聚簇索引是一种数据存储方式,InnoDB的聚簇索引就是按照主键顺序构建的B+Tree结构
B+Tree的叶子节点就是行记录,行记录和主键值紧凑地存储在一起。 这也意味着 InnoDB 的主键索引就是数据表本身,它按主键顺序存放了整张表的数据,占用的空间就是整个表数据量的大小
InnoDB的表要求必须要有聚簇索引:如果表定义了主键,则主键索引就是聚簇索引
如果表没有定义主键,则第一个非空unique列作为聚簇索引。否则InnoDB会从建一个隐藏的row-id作为聚簇索引与InnoDB表存储不同,MyISAM数据表的索引文件和数据文件是分开的,被称为非聚簇索引结构
2.3 辅助索引
InnoDB辅助索引,也叫作二级索引,是根据索引列构建 B+Tree结构。
但在 B+Tree 的叶子节点中只存了索引列和主键的信息。二级索引占用的空间会比聚簇索引小很多,通常创建辅助索引就是为了提升查询效率。一个表InnoDB只能创建一个聚簇索引,但可以创建多个辅助索引
2.4 回表查询
通过索引查询主键值,然后再去聚簇索引查询记录信息
2.5 覆盖索引
只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快,这就叫做索引覆盖。
实现索引覆盖最常见的方法就是:将被查询的字段,建立到组合索引
2.6 最左前缀原则
复合索引使用时遵循最左前缀原则,最左前缀顾名思义,就是最左优先,即查询中使用到最左边的列,那么查询就会使用到索引,如果从索引的第二列开始查找,索引将失效
2.7 Like查询
面试题:MySQL在使用like模糊查询时,索引能不能起作用?
MySQL在使用Like模糊查询时,索引是可以被使用的,只有把%字符写在后面才会使用到索引
2.8 NULL查询
面试题:如果MySQL表的某一列含有NULL值,那么包含该列的索引是否有效?
对MySQL来说,NULL是一个特殊的值,从概念上讲,NULL意味着“一个未知值”,它的处理方式与其他值有些不同。
比如:不能使用=,这样的运算符,对NULL做算术运算的结果都是NULL,count时不会包括NULL行等,NULL比空字符串需要更多的存储空间等。
NULL列需要增加额外空间来记录其值是否为NULL。对于MyISAM表,每一个空列额外占用一位,四舍五入到最接近的字节
虽然MySQL可以在含有NULL的列上使用索引,但NULL和其他数据还是有区别的,不建议列上允许为NULL。最好设置NOT NULL,并给一个默认值,比如0和 '' 空字符串等,如果是datetime类型,也可以设置系统当前时间或某个固定的特殊值,例如'1970-01-01 00:00:00'
2.9 索引与排序
MySQL查询支持filesort和index两种方式的排序filesort是先把结果查出,然后在缓存或磁盘进行排序操作,效率较低
filesort有两种排序算法:双路排序和单路排序
(1)双路排序:需要两次磁盘扫描读取,最终得到数据。第一次将排序字段读取出来,然后排序;第二次去读取其他字段数据。
(2)单路排序:从磁盘查询所需的所有列数据,然后在内存排序将结果返回。如果查询数据超出缓存sort_buffer,会导致多次磁盘读取操作,并创建临时表,最后产生了多次IO,反而会增加负担。解决方案:少使用select *;增加sort_buffer_size容量和max_length_for_sort_data容量。
使用index是指利用索引自动实现排序,不需另做排序操作,效率会比较高。
如果我们Explain分析SQL,结果中Extra属性显示Using filesort,表示使用了filesort排序方式,需要优化。如果Extra属性显示Using index时,表示覆盖索引,也表示所有操作在索引上完成,也可以使用index排序方式,建议大家尽可能采用覆盖索引
以下几种情况,会使用index方式的排序
(1)ORDER BY 子句索引列组合满足索引最左前列
explain select id from user order by id; //对应(id)、(id,name)索引有效
(2)WHERE子句+ORDER BY子句索引列组合满足索引最左前列
explain select id from user where age=18 order by name; //对应 (age,name)索引
以下几种情况,会使用filesort方式的排序
(1)对索引列同时使用了ASC和DESC
explain select id from user order by age asc,name desc; //对应 (age,name)索引
(2)WHERE子句和ORDER BY子句满足最左前缀,但where子句使用了范围查询(例如>、
explain select id from user where age>10 order by name; //对应 (age,name)索引
(3)ORDER BY或者WHERE+ORDER BY索引列没有满足索引最左前列
explain select id from user order by name; //对应(age,name)索引
(4)使用了不同的索引,MySQL每次只采用一个索引,ORDER BY涉及了两个索引
explain select id from user order by name,age; //对应(name)、(age)两个索引
(5)WHERE子句与ORDER BY子句,使用了不同的索引
explain select id from user where name='tom' order by age; //对应 (name)、(age)索引
(6)WHERE子句或者ORDER BY子句中索引列使用了表达式,包括函数表达式
explain select id from user order by abs(age); //对应(age)索引