目录
1.概述
2索引结构:
3.索引分类
4.索引语法
5.sql性能分析
6.索引使用
6.1最左前缀法则:!!!重点!!!
6.2范围查询
6.3索引失效情况
6.4sql提示
6.5覆盖索引
6.6前缀索引
6.7单列索引与联合索引
索引(index)是帮助MySQL高效获取数据的数据结构(有序)。
b加树的构建方式
如果存在主键,主键索引就是聚集索引。如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。如果表没有主键,或没有合适的唯一索引,则InnoDB会自动生成一个rowid作为隐藏的聚集索引。
回表查询:这种先到二级索引中查找数据,找到主键值,然后再到聚集索引中根据主键值,获取数据的方式,就称之为回表查询。
//创建索引
CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (
index_col_name,... ) ;
//查看索引
SHOW INDEX FROM table_name ;
//删除索引
DROP INDEX index_name ON table_name ;
5.1sql执行频率
我们可以查看到当前数据库到底是以查询为主,还是以增删改为主,从而为数据库优化提供参考依据。
-- session 是查看当前会话 ;
-- global 是查询全局数据 ;
SHOW GLOBAL STATUS LIKE 'Com_______';
-- Com后面是七个—— 占位符
5.2慢查询日志
# 查看慢查询日志开关
show variables like 'slow_query_log'
# 开启MySQL慢日志查询开关
slow_query_log=1
# 设置慢日志的时间为2秒,SQL语句执行时间超过2秒,就会视为慢查询,记录慢查询日志
long_query_time=2
#改变开关后重启sql
systemctl restart mysql
#打开日志
/var/lib/mysql/localhost-slow.log
#动态展示日志
tail -f localhost-slow.log
5.3 profiles
show profiles 能够在做SQL优化时帮助我们了解时间都耗费到哪里去了
--打开开关
SET profiling = 1;
-- 查看每一条SQL的耗时基本情况
show profiles;
-- 查看指定query_id的SQL语句各个阶段的耗时情况
show profile for query query_id;
-- 查看指定query_id的SQL语句CPU的使用情况
show profile cpu for query query_id;
5.4explain
EXPLAIN 或者 DESC命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行过程中表如何连接和连接的顺序。
-- 直接在select语句之前加上关键字 explain / desc
EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件 ;
结果分析:
type字段,一般主键索引的查询为const,其余字段索引的查询为ref,全表查询为all
如果索引了多列(联合索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将会部分失效(后面的字段索引失效)。
例如创建联合索引:CREATE INDEX idx_user_pro_age_sta ON tb_user(profession,age,status);
1.查询时,最左变的列,也就是profession必须存在,否则索引全部失效。(相当于没有索引全表查询了)
例如:explain select * from tb_user where age = 31 and status = '0'; 不会用到索引。
2.查询时,中间不能跳过某一列,否则该列后面的字段索引将失效,后面的字段不会走索引。
例如:explain select * from tb_user where profession = '软件工程' and status = '0'; 就只用了profession的索引。
注意上面说的左右时创建索引时的左右,查询的字段顺序不影响,例如下面思考题:
联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效。允许的情况,推荐>=,<=
--status字段不会走索引,部分失效
explain select * from tb_user where profession = '软件工程' and age > 30 and status= '0';
--全部有效
explain select * from tb_user where profession = '软件工程' and age >= 30 and status= '0';
1.索引列运算,例如:
explain select * from tb_user where substring(phone,10,2) = '15'; --失效
2.索引字符串不加单引号,隐式转换导致索引失效
explain select * from tb_user where profession = '软件工程' and age = 31 and status
= '0';--有效
explain select * from tb_user where profession = '软件工程' and age = 31 and status
= 0;--失效
3.模糊查询的时候有模糊%在前面
explain select * from tb_user where profession like '软件%';--有效
explain select * from tb_user where profession like '%工程';--失效
explain select * from tb_user where profession like '%工%';--失效
4.or,or的左右一侧使用了索引,一侧没有使用
explain select * from tb_user where id = 10 or age = 23;--age没有索引,则id的主键索引也失效
5.数据分布导致,sql认为全表搜索更快时
例如profession字段大部分都是非空的:
explain select * from tb_user where profession is null;--走索引
explain select * from tb_user where profession is not null;--不走索引
use index(idx_name):建议sql使用某个索引;
ignore index(idx_name):忽略某个索引
force index(idx_name):强迫使用某个索引
select * from table_name use index(index_name_ziduan) where ziduan = 'ababa';
select * from tb_user ignore index(idx_user_pro) where profession = '软件工程';
select * from tb_user force index(idx_user_pro) where profession = '软件工程';
覆盖索引是指 查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到 。
explain 语句中Extra的含义:
在tb_user表中有一个联合索引 idx_user_pro_age_sta,该索引关联了三个字段
profession、age、status,而这个索引也是一个二级索引,所以叶子节点下面挂的是这一行的主
键id。 所以当我们查询返回的数据在 id、profession、age、status 之中,则直接走二级索引
直接返回数据了,这就是覆盖索引快的原因。 如果超出这个范围,就需要拿id回表查询了。
所以select *一般都需要回表查询(除了直接用聚集索引查
如果建立索引的字段是长文本字段,前缀索引可以有效减少索引占用的空间。
当字段类型为字符串(varchar,text,longtext等)时,有时候需要索引很长的字符串,这会让
索引变得很大,查询时,浪费大量的磁盘IO, 影响查询效率。此时可以只将字符串的一部分前缀,建
立索引,这样可以大大节约索引空间,从而提高索引效率。
例如:
为tb_user表的email字段,建立长度为5的前缀索引。
creat index idx_email on table(email(5));
关于前缀长度的选择 主要是看区分度,例如:
select count(distinct substring(email,1,5)) / count(*) from tb_user ;
可以获得email前五个不同的个数占总个数的比例。
前缀索引经常要回表查询,因为索引没有包含本字符段的全部信息。
单列索引:即一个索引只包含单个列。
联合索引:即一个索引包含了多个列。
例如 查询语句 select id,phone,age from table where phone='123' and age=23;
如果phone和age各建立了单列索引,mysql只会走一个和索引。要回表
建立了联合索引,就走联合索引。上面这个情况就不用回表了
在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引,
而非单列索引。