索引是用于提升数据库查询速度的数据结构,通常是用b+树来存储。具体地,能把索引看成成书的目录,通过目录能迅速找到每个章节每个小结里的内容。通过数据库索引,我们一样能快速找到数据表中指定条件的记录。
第一,使用索引能减少数据库引擎扫描数据表的数据量,反之每个查询都会进行全表扫描,性能就很慢。
第二,经过索引整理后的表数据是排好序的,所以如果对表进行ORDER BY
或GROUP BY
等的操作时,能很快得到所需的结果。
第三,通过索引能把针对磁盘的随机I/O操作转换成顺序I/O
操作,从而能降低磁盘IO
成本,提升效率。
MySQL
索引是在存储引擎这个层面实现的,所以针对索引,每一种MySQL引擎都有不同的实现方式,但一样都能提升性能。
如果用以%
开头的LIKE
语句进行模糊查询,就无法用到索引,如:
- SELECT * FROM student WHERE name LIKE '%Peter%';
-
- SELECT * FROM student WHERE name LIKE '%Tom';
但如果不用以%
为开头的查询语句,就可以使用到索引,如:
SELECT * FROM student WHERE name LIKE 'Peter%';
引入OR
语句后,也无法用到索引。比如下面的语句,字段id
有索引,而字段name
没有创建索引,那么如下SQL语句只能全表扫描,无法用到索引:
SELECT * FROM student id = 10 or name='Tom'
在MySQL
中,大部分情况下索引都是用B-Tree
作为底层数据结构,这块内容比较重要,但网上资料很多,所以就不展开说明了。
1 . 对于数据量比较少(比如就几千),或者查询需求比较少的表,不建议创建索引。
2. 修改频繁,且修改性能远大于查询性能时,不应该再创建索引。
3. 对于一些重复率比较大的字段,比如性别字段,不建议建索引,或者是某字段空值很多,也不建议建索引。
回表是针对MySQL里的Innodb引擎而言的,在InnoDB
引擎的工作方式下,主键索引的叶子节点存储的记录,而普通索引的叶节点存储的主键索引的地址。
当用主键进行查询时,只需搜索主键索引的搜索树,就能直接得到记录的数据。
但如果用普通索引进行查询时,用搜索普通索引的B树得到主键对应的地址之后,还要再用该主键对主键的B树再次进行搜索,这个过程就叫回表。
聚簇索引的顺序就是数据在磁盘里的存储顺序,并且索引和数据一起存储,用索引能直接得到数据。在一个数据表里,只能建一个聚簇索引,一般来说主键索引就是聚簇索引。
非聚簇索引是指,索引的顺序与数据物理排列的顺序无关,索引文件和数据表里的数据是分开存放,在一个数据表里,除了主键索引外,其他都是非聚簇索。
主键索引的字段里不允许有NULL
值,并且一个数据表里只能有一个主键索引。
加入唯一索引的字段,其值不能有重复。
普通索引但字段可以包含重复的值,也可以包含NULL
值,不过话说回来,如果某字段空值或重复值太多,不建议建索引。
索引本身也需要消耗很多的磁盘空间,而且使用索引时,加载到内存的时候也会占用内存空间。
并且在对表进行修改时,需要重建索引,所以索引越多,写入数据时所需重建索引的代价就越大。
所以一张表的索引数量应当有上限,一般上限数量别超过10个,当然如果某表的查询需求复杂,且时间来不及,可以临时多建些索引来应急,但事后应当修复。
MyISAM
存储引擎针对索引的处理方式是非聚族索引,即索引的空间地址与数据是分开保存的。
而InnoDB
存储引擎的处理方式是聚族索引,即索引地址跟数据是放在一块的,具体地,InnoDB
一般是把表的主键地址和数据放在一块,如果没有主键,则去把unique key
作为主键处理,如果表里也没有创建unique key
,那么就会为表自动创建一个rowid
作为主键来处理。
一般来说,这是对复合索引来讲的,比如通过如下的语句创建了包含复合索引。
- CREATE TABLE demo(
- a INT NOT NOT,
- b INT NOT NOT,
- KEY(a,b)
- );
当用下面的查询语句时,由于WHERE
语句中查询的条件就是联合索引,所以可以很快查询到数据。
SELECT * FROM demo WHERE a=1 AND b=1;
同样,下面的语句也会用到上述的复合索引来提升性能,这是因为MySQL
会按照索引创建的顺序进行排序,然后再根据查询条件从索引最左边开始检测查询条件是否满足该索引,由于字段a
在最左边,所以满足索引。
SELECT * FROM demo WHERE a=1;
但如果用字段b
进行查询时,因为从最左边匹配到的是字段a
,所以MySQL
判断为不满足索引条件,所以该个sql语句不会走索引。
SELECT * FROM demo WHERE b=1;