MySQL官方对索引定义:是存储引擎用于快速查找记录的一种数据结构。需要额外开辟空间和数据维护工作。
a. 普通索引
最基本的索引类型,基于普通字段建立的索引,没有任何限制
b. 唯一索引
索引字段的值必须唯一,但允许有空值 。在创建或修改表时追加唯一约束,就会自动创建对应的唯一索引。
c. 主键索引
一种特殊的唯一索引,不允许有空值。在创建或修改表时追加主键约束即可,每个表只能有一个主键。
d. 复合索引
在多个列上建立索引,这种索引叫做组复合索引(组合索引)。复合索引可以代替多个单一索引,相比多个单一索引复合索引所需的开销更小。
e. 全文索引
查询操作在数据量比较少时,可以使用like模糊查询,但是对于大量的文本数据检索,效率很低。如果使用全文索引,查询速度会比like快很多倍。
和常用的like模糊查询不同,全文索引有自己的语法格式,使用 match 和 against 关键字
select * from user
where match(name) against('aaa');
全文索引使用注意事项:
select * from user
where match(name) against('a*' in boolean mode);
二分查找法也叫作折半查找法,它是在有序数组中查找指定数据的搜索算法。它的优点是等值查询、范围查询性能优秀,缺点是更新数据、新增数据、删除数据维护成本高。
具体过程是:
Hash索引底层是由Hash表来实现的,是根据键值
InnoDB 自适应哈希索引:
InnoDB存储引擎会监控表上各个索引页的查询,当InnoDB注意到某些索引值访问非常频繁时,会在内存中基于B+Tree索引再创建一个哈希索引,使得内存中的 B+Tree 索引具备哈希索引的功能,即能够快速定值访问频繁访问的索引页。
MySQL数据库索引采用的是B+Tree结构,它在B-Tree结构上做了优化改造。
B树 vs B+树
B树结构:
B树的搜索:
B+树结构:
B+树的搜索:
聚簇索引 vs 非聚簇索引
主键索引 vs 辅助索引
InnoDB的索引
在InnoDB中,主键索引采用的是聚簇索引,非主键索引采用辅助索引
对于主键索引,B+Tree的叶子节点就是行记录,行记录和主键值紧凑地存储在一起。 这也意味着 InnoDB 的主键索引就是数据表本身,它按主键顺序存放了整张表的数据,占用的空间就是整个表数据量的大小。
InnoDB的表要求必须要有聚簇索引:
对于非主键索引,采用辅助索引,也叫作二级索引,是根据索引列构建 B+Tree结构。但在 B+Tree 的叶子节点中只存了索引列和主键的信息。二级索引占用的空间会比聚簇索引小很多, 通常创建辅助索引就是为了提升查询效率。一个表InnoDB只能创建一个聚簇索引,但可以创建多个辅助索引。
MyISAM的索引
MyISAM的主键和非主键索引采用的都是非聚簇索引。
MySQL 提供了一个 EXPLAIN 命令,它可以对 SELECT 语句进行分析,并输出 SELECT 执行的详细信息,供开发人员有针对性的优化。
EXPLAIN 命令执行后包含以下参数:
a. select_type
表示查询的类型。常用的值如下:
b. type
表示存储引擎查询数据时采用的方式,常用属性值如下,从上至下效率依次增强:
c. possible_keys
表示查询时能够使用到的索引。注意并不一定会真正使用,显示的是索引名称
d. key
表示查询时真正使用到的索引,显示的是索引名称
e. rows
MySQL查询优化器会根据统计信息,估算SQL要查询到结果需要扫描多少行记录。原则上rows是越少效率越高,可以直观的了解到SQL效率高低
f. key_len
表示查询使用了索引的字节数量。可以判断是否全部使用了组合索引。
g. Extra
表示额外的信息,常见几种如下:
InnoDB辅助索引的叶子节点存储的是主键值和索引字段值,通过辅助索引无法直接定位行记录,通常情况下,需要扫码两遍索引树。
先通过辅助索引定位主键值,然后再通过聚簇索引定位行记录,这就叫做回表查
只需要在一棵索引树上就能获取SQL所需的所有列数据,无需回表,速度更快,这就叫做索引覆盖。
实现索引覆盖最常见的方法就是:将被查询的字段,建立到组合索引
复合索引使用时遵循最左前缀原则,即查询中使用到最左边的列,那么查询就会使用到索引,如果从索引的第二列开始查找,索引将失效。
MySQL在使用Like模糊查询时,索引是可以被使用的,但只有把%字符写在后面才会使用到索引。
select * from user where name like '%o%'; //不起作用
select * from user where name like 'o%'; //起作用
select * from user where name like '%o'; //不起作用
对MySQL来说,NULL是一个特殊的值,从概念上讲,NULL意味着“一个未知值”,它的处理方式与其他值有些不同。比如:不能使用=,<,>这样的运算符,对NULL做算术运算的结果都是NULL,count时不会包括NULL行等,NULL比空字符串需要更多的存储空间等。
虽然MySQL可以在含有NULL的列上使用索引,但NULL和其他数据还是有区别的,不建议列上允许为NULL。最好设置NOT NULL,并给一个默认值,比如0和 ‘’ 空字符串等,如果是datetime类型,也可以设置系统当前时间或某个固定的特殊值,例如’1970-01-01 00:00:00’。
MySQL查询支持filesort和index两种方式的排序,filesort是先把结果查出,然后在缓存或磁盘进行排序操作,效率较低。使用index是指利用索引自动实现排序,不需另做排序操作,效率会比较高
以下几种情况,会使用index方式的排序:
select id from user order by id; //对应(id)、(id,name)索引有效
select id from user where age=18 order by name; //对应(age,name)索引
以下几种情况,会使用filesort方式的排序:
select id from user order by age asc,name desc; //对应(age,name)索引
select id from user where age>10 order by name; //对应(age,name)索引
select id from user order by name; //对应(age,name)索引
select id from user order by name,age; //对应(name)、(age)两个索引
select id from user where name='tom' order by age; //对应(name)、(age)索引
explain select id from user order by abs(age); //对应(age)索引
查看 MySQL 数据库是否开启了慢查询日志和慢查询日志文件的存储位置的命令如下:
SHOW VARIABLES LIKE 'slow_query_log%'
通过如下命令开启慢查询日志:
SET global slow_query_log = ON;
SET global slow_query_log_file = 'OAK-slow.log';
SET global log_queries_not_using_indexes = ON;
SET long_query_time = 10;
开启慢查询日志后,定位到慢查询日志的文件,即可进行慢查询的分析
如何定义慢查询?
确定慢查询之后,即可利用EXPLAIN命令对查询进行分析。
有索引一定查询快吗?
慢查询原因总结:
分页查询使用简单的 limit 子句就可以实现:
SELECT * FROM 表名 LIMIT [offset,] rows
偏移量固定,返回记录量对执行时间的影响
select * from user limit 10000,1;
select * from user limit 10000,10;
select * from user limit 10000,100;
select * from user limit 10000,1000;
select * from user limit 10000,10000;
果查询偏移量变化,返回记录数固定对执行时间的影响
select * from user limit 1,100;
select * from user limit 10,100;
select * from user limit 100,100;
select * from user limit 1000,100;
select * from user limit 10000,100;
分页查询的优化:
select * from user limit 10000,100;
select id from user limit 10000,100;
select * from user limit 10000,100;
select * from user where id>= (select id from user limit 10000,1) limit 100;