对于SQL优化,今天我们先来看下基本知识:
存储引擎就是存储数据、建立索引、更新/查询数据等技术的实现方式。存储引擎基于表,可以以表的维度来进行指定。
查看当前表的存储引擎
-- 查看建表语句,查看存储引擎,默认是InnoDB
show create table emp;
新建表时指定存储引擎
create table 表名(
字段 字段类型 [comment 字段注释]
...
)engine=innodb [comment 表注释];
查看当前数据库支持的存储引擎
show engines;
介绍
特点
文件
介绍
特点
不支持事务,不支持外键
支持表锁,不支持行锁
访问速度快
文件
在选择存储引擎时,需要根据应用系统的特点选择合适的存储引擎,对于复杂的应用系统,还可以根据实际情况选择多种存储引擎进行组合使用。
索引(index),是帮助MySQL高效获取数据的数据结构(有序)。当表没有索引时,查询数据可能是全表查询;当创建索引后,先查索引,根据索引检索到数据,提供获取数据的效率。
优点 | 缺点 |
---|---|
提高数据检索的效率,降低数据库的IO成本 | 索引列也要占用空间 |
通过索引列对数据进行排序,降低数据排序的成本,降低CPU的消耗 | 索引大大提高了查询效率,同时也降低更新表的速度,如对表进行insert、update、delete时,效率降低 |
MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的结构。
二叉树数据结构
左侧的叶子节点小于父节点
二叉树在顺序插入时,会形成一个链表,查询性能大大降低,大数据量情况下,层级较深,检索速度慢。红黑树,平衡二叉树,可以解决形成链表,但是仍然有大数据量情况下,层级较深,检索速度较慢的问题。
B-Tree(多路平衡查找树) 以一棵最大度数(max-degree)为5(5阶)的b-Tree为例(每个节点最多存储4个key,5个指针),可在https://www.cs.usfca.edu/~galles/visualization/BTree.html上查看B-Tree数据结构
B+Tree的特点
以一棵最大度数为4的B+Tree为例,
可在https://www.cs.usfca.edu/~galles/visualization/BPlusTree.html上查看数据结构
MySQL索引数据结构对经典的B+Tree进行了优化,在原来B+Tree的基础上,增加了一个指向相邻子节点的链表指针,就形成了带有顺序的B+Tree,提高区间访问的性能。
Hash结构,哈希索引就是采用一定的hash算法,将键值换成新的hash值,映射到对应的槽位上,然后存储在hash表中
为什么InnoDB存储引擎使用B+Tree索引结构
在InnoDB中的分类
聚集索引的选取规则
聚集索引和二级索引的区别
回表查询
如下示例:
-- user 表中,id为主键,并且给name增加了索引
– 该查询,可直接使用聚集索引(id为主键)进行查询
select * from user where id = 10;
– 该查询,需要先使用二级索引,然后回表,使用聚集索引查询
select * from user where name = ‘小明’;
InnoDB主键索引的B+Tree高度为多高?
假设,一行数据大小为1k,一页中可以存储16行这样的数据,InnoDB的指针占用6个字节的空间,主键即使为bigint,占用字节数为8。由于每页的大小为16K。
创建索引
create [unique|fulltext] index index_name on table_name(字段1,字段2,...);
查看索引
show index from table_name;
删除索引
drop index index_name on table_name;
-- 创建数据库
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) NOT NULL,
`age` int NOT NULL,
`city` varchar(20) DEFAULT NULL,
PRIMARY KEY (`id`)
);
-- 创建索引
create index index_name on user(name);
-- 查看索引
show index from user;
-- 创建索引
create index index_name_age_city on user(name,age,city);
-- 删除索引
drop index index_name_age_city on user;
如果索引了多列(联合索引),要遵循最左前缀法则。最左前缀法则指:查询从索引的最左列开始,并不跳过索引中的列。如果跳跃某一列,索引将部分失效(后面的字段索引失效)
比如在user表中,创建的索引是id+name+age
联合索引总,出现范围查询(<,>),范围查询右侧的列索引失效
-- 即city的这个列索引会失效
explain select * from user where name='夏明' and age > 30 and city ='北京';
-- 在>=、<=的查询中,city的列索引不会失效
explain select * from user where name='夏明' and age >= 30 and city ='北京';
不要在索引列上进行运算操作,索引将失效
create index index_age on user(age);
explain select * from user where substr(user.age,1,1)='3';
字符串类型字段使用时,不加引号,索引将失效
create index index_age on user(name,age,status);
-- 可以使用索引
explain select * from test.user where name='夏明' and age = 30 and status ='1';
-- 部分索引失效
explain select * from test.user where name='夏明' and age = 30 and status =1;
如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配的话,索引会失效。
create index index_name on test.user(name);
explain select * from test.user where user.name like '张%';
-- 索引失效
explain select * from test.user where user.name like '%三';
-- 索引失效
explain select * from test.user where user.name like '%三%';
用or分割开的查询条件,如果or的一侧没有索引(前边有后边没有;前边没有后边有),那索引会失效
-- 只有id为索引,使用or连接查询时,索引失效
explain select * from test.user where id = 1 or name='夏明';
如果MySQL评估使用所有会比全表扫描还慢,则不会使用索引
create index index_age on test.user(age);
-- 由于所有的数据中age大于10,
explain select * from test.user where age >= 10;
-- 修改条件后,就使用到了索引
explain select * from test.user where age >= 30;
提示存储引擎使用哪个索引:
-- 创建2个索引
create index index_name_age_city on user(name,age,city);
create index index_name on user(name);
explain select * from test.user where name='夏明';
-- 建议使用索引
explain select * from test.user use index (index_name) where name='夏明';
-- 忽略使用索引
explain select * from test.user ignore index (index_name) where name='夏明';
-- 强制使用索引
explain select * from test.user force index (index_name) where name='夏明';
尽量使用覆盖索引(查询使用了索引,并且查询的字段包含索引字段),减少使用select(*) Extra中的信息
实际的业务场景中,如果存在多个查询,考虑针对于查询字段建立索引时,建议建立联合索引 多条件查询时,MySQL优化器会评估哪个字段的索引效率更高,会选择该索引完成本次查询