写在前面的话

啥是索引?以一本书为例,如果想要找到某一指定章节的某一小节,书薄还好,如果书厚,可能就会找的头皮发麻。于是便出现了目录,让用户更容易查找到自己所需要的东西。索引就类似一张表的目录。其存在的意义就是优化查询速度,所以在学习的时候,只要一直记住这个类比,就相对更容易理解一些。

关于索引

在索引中,常见的算法有: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 inlike '%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:索引和执行计划的更多相关文章

  1. python/MySQL(索引、执行计划、BDA、分页)

    ---恢复内容开始--- python/MySQL(索引.执行计划.BDA.分页) MySQL索引: 所谓索引的就是具有(约束和加速查找的一种方式)   创建索引的缺点是对数据进行(修改.更新.删除) ...

  2. mysql的索引和执行计划

    一.mysql的索引 索引是帮助mysql高效获取数据的数据结构.本质:索引是数据结构 1:索引分类 普通索引:一个索引只包含单个列,一个表可以有多个单列索引. 唯一索引:索引列的值必须唯一 ,但允许 ...

  3. 第九课——MySQL优化之索引和执行计划

    一.创建索引需要关注什么? 1.关注基数列唯一键的数量: 比如性别,该列只有男女之分,所以性别列基数是2: 2.关注选择性列唯一键与行数的比值,这个比值范围在0~1之前,值越小越好: 其实,选择性列唯 ...

  4. MySQL——通过EXPLAIN分析SQL的执行计划

    在MySQL中,我们可以通过EXPLAIN命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序. 下面分别对EXPLAIN命令结果的每一列进行说明: ...

  5. [转]Mysql中的SQL优化与执行计划

    From : http://religiose.iteye.com/blog/1685537 一,如何判断SQL的执行效率? 通过explain 关键字分析效率低的SQL执行计划. 比如: expla ...

  6. Mysql学习---视图/触发器/存储过程/函数/执行计划/sql优化 180101

    视图 视图: 视图是一个虚拟表(非真实存在),动态获取数据,仅仅能做查询操作 本质:[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需使用[名称]即可获取结果集,并可以将其当作表来使用.由 ...

  7. 高性能可扩展mysql 笔记(六) SQL执行计划及分页查询优化、分区键统计

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 常见业务处理 一.使用数据库处理常见业务: 案例: 如何对评论进行分页展示 使用 EXPLAIN 获得s ...

  8. SQL Server索引的执行计划

    如何知道索引有问题,最直接的方法就是查看执行计划.通过执行计划,可以回答表上的索引是否被使用的问题. (1)包含索引:避免书签查找 常见的索引方面的性能问题就是书签查找,书签查找分为RID查找和键值查 ...

  9. Mongodb索引和执行计划 hint 慢查询

    查询索引 索引存放在system.indexes集合中 > show tables address data person system.indexes 默认会为所有的ID建上索引 而且无法删除 ...

随机推荐

  1. SPA项目开发之动态树、表格、分页

    思路: 1.准备好后台(左侧树,带分页的文章查询) 2.将左侧树的数据绑定到elementui中的menu标签上 3.新增一个自定义组件用来展示文章列表的 4.绑定elementui提供的分页组件来完 ...

  2. PHP作用域和文件夹操作

    1.作用域      1.1变量作用域      1.全局变量:在函数外面       2.局部变量:在函数里面,默认情况下,函数内部是不会访问函数外部的变量       3.超全局变量:可以在函数内 ...

  3. C#WinForm解决跨线程访问控件属性报错

    方式一(在程序初始化构造函数中加一行代码): public Form1() { InitializeComponent(); Control.CheckForIllegalCrossThreadCal ...

  4. ABP进阶教程2 - 组合查询

    点这里进入ABP进阶教程目录 更新数据传输对象 打开应用层(即JD.CRS.Application)的Course\Dto\GetAllCoursesInput.cs //Course数据传输对象(查 ...

  5. 我认为现代IDE编辑器应该具有的几个特性和Visual studio 2010增强

    工作中要使用 VS 2010, 有好多年没有使用Visual studio 了, 试了一小会, 发现VS 2010 缺少不少现代IDE应有的特性, 我认为重要的是下面几个特性, VS2010 已经是1 ...

  6. cluster集群基本概念

    cluster集群种类: 1,LB(Load Balance)负载均衡集群: 弱点:当横向扩展到一定机器后,发现在怎么横向加机器也没有效果的时候,瓶颈就卡在分发的服务器上了,也就是LB机器上了,如何解 ...

  7. Ubuntu安装DaVinci Resolve

    安装DaVinci Resolve所需依赖 sudo apt install libssl1.0.0 ocl-icd-opencl-dev fakeroot xorriso 下载MakeResolve ...

  8. 【cf570】D. Tree Requests(dsu on tree)

    传送门 题意: 给出一个以\(1\)为根的有根树.之后有\(m\)个询问,每个询问为\(v_i,h_i\),需要回答以\(v_i\)为根的子树中,深度为\(h_i\)的那些结点所代表的字符能否构成回文 ...

  9. [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 ...

  10. C++ class外的==重载,判断相等,测试等于,重载示例。二元操作符

    #include <iostream> // overloading "operator == " outside class // == 是二元操作符 /////// ...