写在前面的话

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

关于索引

在索引中,常见的算法有: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. 屏幕输入转换为int//方法大注释

    可以使用两种方法: using System; namespace 方法测试 { class Program { static void Main(string[] args) { Console.W ...

  2. C#比较两个对象中的指定字段值是否相等

    一.创建CompareFieldAttribute标识要比较的字段 using System; namespace CompareObjField { /// <summary> /// ...

  3. PlayJava Day006

    今日所学: /* 2019.08.19开始学习,此为补档. */ 构造方法没有返回值(即return为空). this:实例(对象)的引用. JVM:①static方法区:存静态数据   ②栈区:引用 ...

  4. QNetworkRequest加Authorization头,适应Rest风格的API

    Rest是无状态的.Rest的请求之间不应该有依赖,在调用一个请求前,不需要一定要去提前调用另外一个请求.Rest里面不应该有 session,特别是Rest请求不应该保存信息在sesssion里,以 ...

  5. [20190523]修改参数后一些细节注意2.txt

    [20190523]修改参数后一些细节注意2.txt --//上午想模拟链接遇到的情况,链接http://blog.itpub.net/267265/viewspace-2645262/--//就是修 ...

  6. 在emacs 里使用gdb

    在emacs 里使用gdb M-x gdb就在emacs里启动了gdb 在gdb窗口里shell-mode的命令都适用 启动gdb后,再启动minor mode:M-x gud-tooltip-mod ...

  7. c++ 模板特化与局部特化

    c++ 模板特化与局部特化 模板的由来是要处理泛化,也就是任何类型都可以处理.但是泛化的同时,如果针对某种特殊的类型,又更加效率的处理方法.c++提供针对特殊的类型,可以定义不同的处理方法.针对某种特 ...

  8. nginx 与 uWsgi 详解

    什么是nginx nginx是一个开源的,支持高性能,高并发的代理服务软件 nginx不但是一个优秀的web服务软件,还可以作为反想代理和负载均衡,以及缓存服务或使用 为什么使用nginx 支持高并发 ...

  9. 非ssl给163发邮件,报错,无解ing

    #给163发送邮件import smtplibfrom email.mime.text import MIMETextnam='15527721040@163.com'send='1552772104 ...

  10. Python企业面试题(系列目录)

    本系列计划把Python面试中出现频率比较高知识点整理出来,以便各位童鞋复习和练习: [第1题] Python内存管理以及垃圾回收机制 [第2题] 链表的逆置 [第3题] 两个队列创建一个栈 [第4题 ...