MySQL for OPS 03:索引和执行计划
写在前面的话
啥是索引?以一本书为例,如果想要找到某一指定章节的某一小节,书薄还好,如果书厚,可能就会找的头皮发麻。于是便出现了目录,让用户更容易查找到自己所需要的东西。索引就类似一张表的目录。其存在的意义就是优化查询速度,所以在学习的时候,只要一直记住这个类比,就相对更容易理解一些。
关于索引
在索引中,常见的算法有:B 树,Hash,R 树,Full text,GIS 等。只需要记两三个即可。
其中最重要的就是 B 树索引,可再度分为:B- 树,B+ 树(在 > < like 等查找中性能更优),B* 树
目前最多的就是 B+ 树,其结构可类比为树的:根(Root),枝(Internal),叶(Leaf)
树状结构如图(图片来自互联网):
在功能上面,索引可分为:辅助索引和聚集索引
辅助索引创建 B 树过程:
当用户执行创建索引操作:alter table t1 add index idx(id);
1. 提取索引列(id 列)的值,进行排序。
2. 向叶子节点申请数据页(16K),然后将排序后的值存储到叶子节点的数据页中,并和真实数据进行关联。
3. 向枝节点和根节点申请数据页,将下层中单页最小值存储进去,如此类推。
聚集索引创建 B 树过程:
聚集索引创建的前提是列为主键或者唯一键,一般为主键,如 ID 字段。
一旦表中有主键列,那么在数据写入的时候就会按照主键的顺序写到磁盘的数据页中。
聚集索引叶节点直接就是真实数据页,减少了 B 树层级。
两者的区别:
聚集索引只能一个,要求非空唯一,一般是主键。辅助索引可以配置多个。
聚集索引叶子节点直接就是真实数据页,辅助索引则是抽离出来排序后的数据。
辅助索引分类:
1. 普通的单列索引。
2. 联合索引(多列索引),用多个列建立一个索引,如:select * from t1 where a=xx and b=xx and c=xx; 这种查询。
3. 唯一索引(unique index):索引列的值都是唯一。
索引树高度影响因素:
1. 数据行数影响,解决办法:分库分表,分布式
2. 索引列值过长,解决办法:前缀索引
3. 数据类型:变长字符串使用了 char,解决办法:变长使用 varchar
管理索引
查看表的索引情况:
show index from city;
-- 或者
desc city;
结果:
其中:PRI 是主键索引(聚集索引),UNI 是唯一索引(辅助索引),MUL 是辅助索引。
1. 创建普通索引:
alter table city add index idx_name(name);
此时查看创建情况:
注意:同一列可以创建多个索引,但是没意义。同一个表中索引名字必须唯一。
2. 删除索引:
-- 创建一个测试索引
alter table city add index idx_name1(name); -- 删除测试索引
alter table city drop index idx_name1;
3. 创建多列联合索引:
alter table city add index idx_d_p(District,Population);
此时查看:
注意:索引列的顺序可能会影响 SQL 最终是否会走该索引。
4. 创建前缀索引:
alter table city add index idx_di(District(5));
注意:前缀索引必须是字符串,不能是数字:
5. 创建唯一索引:
alter table city add unique index idx_uni_id(id);
查看:
查看某列的重复情况以参考是否适合做索引列:
select name,count(id) from city group by name having count(id)>1 order by count(id) desc;
查看重复次数:
压力测试:
mysqlslap --defaults-file=/etc/my.cnf --concurrency=100 --iterations=1 --create-schema='库名' --query="select * from 库名.表名 where 字段名='值'" engine=innodb --number-of-queries=2000 -uroot -p -verbose
100 个并发查询,一共查询 2000 次,没索引 100 万数据测试耗时 700s。加索引后为 0.1 秒,性能提升恐怖。
关于执行计划
执行计划的作用在于帮助分析 SQL 是否走索引以及是否走正确的的索引,进而优化业务逻辑。
以 world 库为例,先删除之前 city 表创建的索引:
查看表索引:
看看数据库优化器最终选择的执行计划:
desc select * from city where Name="Shanghai";
只需在执行的 SQL 前加 desc:
其中重要字段的含义:
possible_keys:可能会用到的索引
key:真正使用到的索引
type:索引类型
Extra:额外信息
type 字段详解:(性能逐级提升)
1. ALL:全表扫描,不走索引
a. 查询没有索引的 name 字段:
select * from city where Name="Shanghai";
b. 查询语句中辅助索引使用到:<>,not in,like '%xxx'
desc select * from city where countrycode <> "CHN";
desc select * from city where countrycode not in ("CHN","USA");
desc select * from city where countrycode like "%CH%";
如图:
但在聚集索引字段使用则会走索引,如:
desc select * from city where id <> 100;
如图:
2. INDEX:全索引扫描
a. 查询需要获取整个索引树时:
desc select countrycode from city;
如图:
b. 联合索引中,任何一个非最左列作为查询条件:
假如索引 idx_a_b_c(a,b,c) 其实相当于建立了索引:a,ab,abc。此时 a 就是最左列,此时:
select * from t1 where b=xxx;
3. RANGE:索引范围扫描
辅助索引:<,>,>=,<=,like,in,or
主键:<>,not in
注意:前两种能享受到 B+ 树的优势,第三种 in 方法不会,为了优化可以写成:
desc select * from city where countrycode="CHN" union all select * from city where countrycode="USA";
结果:
4. ref:非唯一性索引,等值查询
desc select * from city where countrycode="CHN";
结果:
5. eq_ref:多表连接时,连接条件使用唯一索引
desc select a.name,b.name from city as a join country as b on a.countrycode=b.code where a.population<100;
结果:
6. const:唯一索引等值查询
desc select * from city where id=10;
结果:
Extra 字段说明:
desc select * from city where countrycode="CHN" order by population;
在使用排序的时候会发现,在 extra 字段出现:filesort (文件排序)
说明在使用 order by 的时是没有走索引的,之前说过,辅助索引会将索引列的值抽离出来进行排序。
但 where 条件用了索引,由此得出:在多个条件的时候,优化器只会选择其中一个索引。
解决办法:将多个条件中字段创建联合索引:
alter table city add index idx_c_p(countrycode,population);
desc select * from city where countrycode="CHN" order by population;
再度查看:
同理在 group by,distinct 中也一样。
联合索引中的特殊情况:
1. select * from t1 where a=xxx and b=xxx; 这种情况下,创建索引:
alter table t1 add index idx_a_b(a,b); 和 alter table t1 add index idx_b_a(b,a); 效果一样。
where 会自动调整顺序使其满足索引需求,但创建时应将唯一值更多放在前面。
2. 如果 where 中出现不等值查询:select * from t1 where k1 > 100 and k2="aaa";
创建索引应该:alter table t1 add index idx_2_1(k2,k1);
并将语句 k2="aaa" 放前面,否则 > 在前会卡住索引,导致后面条件不走索引。
3. 如果语句中存在多个子句,则需要按照执行顺序建立索引。
线上数据库卡顿解决思路:
1. show processlist; 或者 show full processlist; 查看问题 SQL,如果暂时无法解决,可先 kill 掉。
2. 使用 desc 或者 explain 分析 SQL 走索引的情况,如果没走索引,通过分析后建立索引。
特定的时间段慢的解决思路:
可以通过后面的 slowlog 找到慢 SQL,分析语句走索引情况和耗时情况,进行修改。
建立索引的原则
1. 建表时一定要有主键,一般采用无关列。
2. 尽量选择唯一性索引,如果非要使用重复值较多的,可将表逻辑拆分,也可将此列和其他列做联合索引。
3. 为经常需要 where / order by / group by / join on 等操作的字段建立索引。
4. 索引字段很长,尽量采用前缀索引。
5. 索引不是越多越好,索引越多,越占空间,修改表越慢,可使用 percona-toolkit 的 pt-duplicate-key-checker 进行索引清理。
6. 大表加索引需避开业务高峰期。
7. 尽量避免在经常更新的列上面加索引。
不走索引的情况
1. 没有查询条件或者条件未建立索引。
2. 查询结果集是原表中大部分数据,数据超过 25%,优化器会觉得没必要走索引。可使用 limit 或存 redis 解决。
3. 索引失效,导致数据不真实。如果表经常修改,容易导致索引失效,需要删除重建解决。
4. 查询条件使用函数在索引列上面,或则对索引列进行 + - * / 计算等,如:select * from t1 where id-1=9;
5. 隐式转换导致索引失效,如号码一般是 varchar 保存全数字,通过 select * from t1 where phone=120; 或 where phone='120'; 结果一致,但前者不走索引。
6. <>,not in 是不走索引的,> < in 这些也有可能不走,后者尽量使用 union all 优化。
7. like 中 % 在前面不走索引,如 like "%HN"。
小结
本章节索引和执行计划简直是 MySQL 优化中重中之重,当然在数据库小的时候还不明显,当数据量大起来以后,质的飞跃。
MySQL for OPS 03:索引和执行计划的更多相关文章
- python/MySQL(索引、执行计划、BDA、分页)
---恢复内容开始--- python/MySQL(索引.执行计划.BDA.分页) MySQL索引: 所谓索引的就是具有(约束和加速查找的一种方式) 创建索引的缺点是对数据进行(修改.更新.删除) ...
- mysql的索引和执行计划
一.mysql的索引 索引是帮助mysql高效获取数据的数据结构.本质:索引是数据结构 1:索引分类 普通索引:一个索引只包含单个列,一个表可以有多个单列索引. 唯一索引:索引列的值必须唯一 ,但允许 ...
- 第九课——MySQL优化之索引和执行计划
一.创建索引需要关注什么? 1.关注基数列唯一键的数量: 比如性别,该列只有男女之分,所以性别列基数是2: 2.关注选择性列唯一键与行数的比值,这个比值范围在0~1之前,值越小越好: 其实,选择性列唯 ...
- MySQL——通过EXPLAIN分析SQL的执行计划
在MySQL中,我们可以通过EXPLAIN命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序. 下面分别对EXPLAIN命令结果的每一列进行说明: ...
- [转]Mysql中的SQL优化与执行计划
From : http://religiose.iteye.com/blog/1685537 一,如何判断SQL的执行效率? 通过explain 关键字分析效率低的SQL执行计划. 比如: expla ...
- Mysql学习---视图/触发器/存储过程/函数/执行计划/sql优化 180101
视图 视图: 视图是一个虚拟表(非真实存在),动态获取数据,仅仅能做查询操作 本质:[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用.由 ...
- 高性能可扩展mysql 笔记(六) SQL执行计划及分页查询优化、分区键统计
个人博客网:https://wushaopei.github.io/ (你想要这里多有) 常见业务处理 一.使用数据库处理常见业务: 案例: 如何对评论进行分页展示 使用 EXPLAIN 获得s ...
- SQL Server索引的执行计划
如何知道索引有问题,最直接的方法就是查看执行计划.通过执行计划,可以回答表上的索引是否被使用的问题. (1)包含索引:避免书签查找 常见的索引方面的性能问题就是书签查找,书签查找分为RID查找和键值查 ...
- Mongodb索引和执行计划 hint 慢查询
查询索引 索引存放在system.indexes集合中 > show tables address data person system.indexes 默认会为所有的ID建上索引 而且无法删除 ...
随机推荐
- SPA项目开发之动态树、表格、分页
思路: 1.准备好后台(左侧树,带分页的文章查询) 2.将左侧树的数据绑定到elementui中的menu标签上 3.新增一个自定义组件用来展示文章列表的 4.绑定elementui提供的分页组件来完 ...
- PHP作用域和文件夹操作
1.作用域 1.1变量作用域 1.全局变量:在函数外面 2.局部变量:在函数里面,默认情况下,函数内部是不会访问函数外部的变量 3.超全局变量:可以在函数内 ...
- C#WinForm解决跨线程访问控件属性报错
方式一(在程序初始化构造函数中加一行代码): public Form1() { InitializeComponent(); Control.CheckForIllegalCrossThreadCal ...
- ABP进阶教程2 - 组合查询
点这里进入ABP进阶教程目录 更新数据传输对象 打开应用层(即JD.CRS.Application)的Course\Dto\GetAllCoursesInput.cs //Course数据传输对象(查 ...
- 我认为现代IDE编辑器应该具有的几个特性和Visual studio 2010增强
工作中要使用 VS 2010, 有好多年没有使用Visual studio 了, 试了一小会, 发现VS 2010 缺少不少现代IDE应有的特性, 我认为重要的是下面几个特性, VS2010 已经是1 ...
- cluster集群基本概念
cluster集群种类: 1,LB(Load Balance)负载均衡集群: 弱点:当横向扩展到一定机器后,发现在怎么横向加机器也没有效果的时候,瓶颈就卡在分发的服务器上了,也就是LB机器上了,如何解 ...
- Ubuntu安装DaVinci Resolve
安装DaVinci Resolve所需依赖 sudo apt install libssl1.0.0 ocl-icd-opencl-dev fakeroot xorriso 下载MakeResolve ...
- 【cf570】D. Tree Requests(dsu on tree)
传送门 题意: 给出一个以\(1\)为根的有根树.之后有\(m\)个询问,每个询问为\(v_i,h_i\),需要回答以\(v_i\)为根的子树中,深度为\(h_i\)的那些结点所代表的字符能否构成回文 ...
- [C3] Andrew Ng - Neural Networks and Deep Learning
About this Course If you want to break into cutting-edge AI, this course will help you do so. Deep l ...
- C++ class外的==重载,判断相等,测试等于,重载示例。二元操作符
#include <iostream> // overloading "operator == " outside class // == 是二元操作符 /////// ...