MySQL索引分析与优化

索引分析

- 准备

先创建三张表:
tb_emp(员工表)
tb_dept(部门表)
tb_desc(描述表)

1. tb_emp(员工表)

DROP TABLE IF EXISTS `tb_emp`;
CREATE TABLE `tb_emp` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`deptid` int(11) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
INSERT INTO `tb_emp`(username,deptid) VALUES (‘Tom‘, ‘1‘);
INSERT INTO `tb_emp`(username,deptid) VALUES (‘Jack‘, ‘1‘);
INSERT INTO `tb_emp`(username,deptid) VALUES (‘Mary‘, ‘2‘);
INSERT INTO `tb_emp`(username,deptid) VALUES (‘Rose‘, ‘3‘);

2.tb_dept(部门表)

    DROP TABLE IF EXISTS `tb_dept`;
    CREATE TABLE `tb_dept` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(20) NOT NULL,
      PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
    -- ----------------------------
    INSERT INTO `tb_dept`(name) VALUES (‘综合部‘);
    INSERT INTO `tb_dept`(name) VALUES (‘研发‘);
    INSERT INTO `tb_dept`(name) VALUES (‘测试‘);
    INSERT INTO `tb_dept`(name) VALUES (‘总裁‘);

3.tb_desc(描述表)

DROP TABLE IF EXISTS `tb_desc`;
CREATE TABLE `tb_desc` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `empid` int(11) DEFAULT NULL,
  `deptid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- ----------------------------
INSERT INTO `tb_desc`(empid,deptid) VALUES (1, 1);
INSERT INTO `tb_desc`(empid,deptid) VALUES (2, 1);
INSERT INTO `tb_desc`(empid,deptid) VALUES (3, 2);
INSERT INTO `tb_desc`(empid,deptid) VALUES (4, 3);

注:为了进行join的分析,这里将员工表与部门表不直接关联,再通过tb_desc(描述表)进行关联。

1.left join

1).首先执行查询。

2).通过explain进行分析。

分析:从explain执行结果可以看出对两表都是用了全表扫描(ALL),并且在tb_desc(描述表)中还使用了join连接缓存,需要进行优化。

但是如何优化?是在左表建立索引还是右表建立索引呢 还是都建立索引?
    ——左连接左表是全有,或许应该在右表建立索引?

3).右表创建索引。

在创建索引后,可以获得比较不错的结果。(type=ref,Extra=Using index)

结论:left join(左连接)情况下,应该在右表(tb_desc)创建索引。

2.right join
通过上面left join的测试结果,我们直接交换两表位置,并将left join改变成right join。

与left join进行对比:

1)在left join下,首先执行tb_emp(左表),type=ALL,因为左连接情况下左表全有,因此我们在tb_desc(右表)创建索引,得到比较理想的效果。

2)在right join下(我们交换了tb_emp和tb_desc的位置),执行顺序:tb_emp(右表)→ tb_desc(左表)。右表type=ALL,因为右连接情况下右表全有,因此在左表(tb_desc,我们交换了位置)创建索引,效果肯定和left join一样。

总结
left join(左连接):右表创建索引。
right join(右连接):左表创建索引。
浓缩得出精华——索引相反建

索引优化

—索引优化的目的主要是让索引不失效

-准备

创建经典的tb_emp表。

DROP TABLE IF EXISTS `tb_emp`;
CREATE TABLE `tb_emp` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(20) NOT NULL,
  `age` int(11) NOT NULL,
  gender varchar(10) NOT NULL,
  email varchar(20),
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

------------------------------

INSERT INTO `tb_emp` (name,age,gender,email) VALUES (‘Tom‘, ‘22‘,‘male‘,‘[email protected]‘);
INSERT INTO `tb_emp` (name,age,gender,email) VALUES (‘Mary‘, ‘21‘,‘female‘,‘[email protected]‘);
INSERT INTO `tb_emp` (name,age,gender,email) VALUES (‘Jack‘, ‘27‘,‘male‘,‘[email protected]‘);
INSERT INTO `tb_emp` (name,age,gender,email) VALUES (‘Rose‘, ‘23‘,‘female‘,‘[email protected]‘);

:创建了tb_emp表,并插入了4条数据。

1.最佳左前缀法则
1)定义:在创建了多列索引的情况下,查询从索引的最左前列开始且不能跳过索引中的列。

最佳左前缀法则就是说如果创建了多个索引,在使用索引时要按照创建索引的顺序来使用,不能缺少或跳过,当然如果只使用最左边的索引列,也就是第一个索引是可以的,通俗理解:“带头大哥不能死,中间兄弟不能断”。要点:“头不能掉”。
用案例进行说明

2)创建组合索引,并执行explain。

Case 1:

分析:

①索引的创建顺序为name,age,gender;

②直接使用name(带头大哥)作为条件,可以看到type=ref,key_len=82,ref=const,效果还不错。

Case 2:

分析:

没使用带头大哥(name),直接用兄弟,type=ALL,为全表扫描。

Case 3:

分析:

①对比上面两句sql语句可发现:我们使用:火车头(name)和中间车厢(age)、火车头(name)和车尾(gender)。

②虽然type=ref,但是观察key_len和ref两项,并对比Case1中的结果,可得出在使用火车头(name)和车尾(gender)时,只使用了部分索引也就是火车头(name)的索引。

③通俗理解:火车头单独跑没问题,火车头与直接相连的车厢一起跑也没问题,但是火车头与车尾,如果中间没有车厢,只能火车头自己跑。

Case 4:

分析:

火车头加车厢加车尾,三者串联,就变成了奔跑的小火车。type=ref,key_len=128,ref=const,const,const。

最佳左前缀法则总结:带头大哥不能死,中间兄弟不能断;带头大哥可跑路,老二也可跟着跑,其余兄弟只能死。

2.不要在索引列上做任何操作

在索引列上做任何操作(计算、函数、(自动or手动)类型转换),会导致索引失效从而转向全表扫描。

Case 1:

分析:

这里使用了函数计算,type=ALL,导致索引失效。

Case 2:

分析:

将name=‘Tom’的值修改为‘123’,使用sql后,发生了类型转换,type=ALL,导致全表扫描。

结论:在索引列上做任何操作,都会导致索引失效转向全表扫描。

3.范围右边全失效

存储引擎不能使用索引中范围右边的列,也就是说范围右边的索引列会失效。

Case 1:

Case 2:

Case 3:

Case 4:

对以上4个case进行分析:

①条件单独使用name时,type=ref,key_len=82,ref=const。

②条件加上age时(使用常量等值),type=ref,key_len=86,ref=const,const。

③当全值匹配时,type=ref,key_len=128,ref=const,const,const。说明索引全部用上,从key_len与ref可以看出。

④当使用范围时(age>27),type=range,key_len=86,ref=Null,与Case 1、Case2和Case3可知,使用了部分索引,但gender索引没用上(与Case 3对比)。

结论:范围右边的索引列失效。

4.尽量使用覆盖索引

尽量使用覆盖索引(查询列和索引列尽量一致,通俗说就是对A、B列创建了索引,然后查询中也使用A、B列),减少select *的使用。

Case 1:

Case 2:

分析:

对比Case1和Case2,Case1使用select *,Case2使用覆盖索引(查询列与条件列对应),可看到Extra从Null变成了Using index,提高检索效率。

5.使用不等于(!=或<>)会使索引失效

结论:使用!=会使type=ALL,key=Null,导致全表扫描,并且索引失效。

6.is null 或 is not null也无法使用索引
Case 1:

Case 2:

分析:

在使用is null的时候,索引完全失效,使用is not null的时候,type=ALL全表扫描,key=Null索引失效。

这里的例子可能有点特殊,具体情况肯能和case上的有所不同,但是还是要注意is null和is not null的使用。

7.like通配符以%开头会使索引失效

Case 1:

Case 2:

Case 3:

分析:

①like的%位置不同,所产生的效果不一样,当%出现在左边的时候,type=ALL,key=Null(全表扫描,索引失效),当%出现在右边的时候,type=range,索引未失效。

②like查询为范围查询,%出现在左边,则索引失效。%出现在右边索引未失效。口诀:like百分加右边。

但是在实际生产环境中,%仅出现在右边可能不能够解决我们的问题,所以解决%出现在左边索引失效的方法:使用覆盖索引。

Case 4:

分析:对比Case1可知,通过覆盖索引type=index,并且使用了Using index,从全表扫描变成了全索引扫描,还是不错的。

Case 5:

分析:这里出现type=index,因为主键自动创建唯一索引。

Case 6:

分析:上面四组explain执行的结果都相同,表明都使用了索引,从这里可以深刻的体会到覆盖索引:完全吻合或者沾边(age),都可以使type=index。

Case 7:

分析:由于只在(name,age,gender)上创建索引,当包含email时,导致结果集偏大(email未建索引)【锅大,锅盖小,不能匹配】,所以type=ALL。

8.字符串不加单引号导致索引失效

Case 1:

分析:上述两条sql语句都能查询出相同的数据。

Case 2:

分析:

通过explain执行结果可以看出,字符串(name)不加单引号在查询的时候,导致索引失效(type=ref变成了type=ALL,并且key=Null),并全表扫描。

结论:varchar类型的字段,在查询的时候不加单引号导致索引失效,转向全表扫描。

9.少用or,用or连接会使索引失效

结论:通过上述explain的执行结果可看出,在使用or连接的时候type=ALL,key=Null,索引失效,并全表扫描。

总结
①全值匹配。

②最佳左前缀法则:带头大哥不能死,中间兄弟不能断;带头大哥可跑路,老二也可跟着跑,其余兄弟只能死。

③索引列上不计算。

④覆盖索引记住用。

⑤不等于、is null、is not null导致索引失效。

⑥like百分加右边,加左边导致索引失效,解决方法:使用覆盖索引。

⑦字符串不加单引号导致索引失效。

⑧少用or,用or导致索引失效。

更多精彩内容;你每先多积累一分,时间越长你与其他人的差距就会越发明显,复利算法应该了解一下

◆MySQL索引分析与优化

◆Laravel 5.4 快速开发简书:

◆360大牛全面解读PHP面试

◆PHP开发高可用高安全App后端下载

◆从原理到场景 系统讲解 PHP 缓存技术

◆微信小程序商城构建全栈应用:Thinkphp5

◆全方位深度剖析PHP7底层源码(已完结)

◆PHP秒杀系统 高并发高性能的极致挑战 下载

◆BAT资深工程师由浅入深分析Tp5&Tp6底层源码 - 分享

◆Swoole入门到实战打造高性能赛事直播平台(完整版)

◆Thinkphp5.0仿百度糯米开发多商家电商平台(完整版)

◆EasySwoole+ElasticSearch打造高性能小视频服务系统

◆手撸基于swoole的分布式框架实现分布式调用(20)讲

业务体系越来越复杂,携程编程,PHP并发编程,MySQL底层优化是架构升级的必经之路

社群有专属的一些关于php架构的视频tp、laravel等主流框架、性能优化、swoole、go等热门进阶的学习资料,帮助上进的PHPer走的更容易一些,可以进裙获取到提升下——646724664

从一个Coder逐步走向CTO或是架构师 必然需要不断越过周遭同阶段的同行,加油!


不定期分享限时内容

★腾讯高级PHP工程师笔试题目

★亿级PV高并发场景订单的处理

★laravel开发天猫商城组件服务

★战旗TV视频直播的架构项目实战

★。。。。。。

原文地址:https://www.cnblogs.com/yuyu6/p/11559996.html

时间: 2024-11-05 00:16:35

MySQL索引分析与优化的相关文章

MYSQL索引分析和优化设计方案

一.什么是索引? 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时 MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里面的记录数量越多,这个操作的代价就越高.如果作为搜索条件的列上已 经创建了索引,MySQL无需扫描任何记录即可迅速得到目标记录所在的位置.如果表有1000个记录,通过索引查找记录至少要比顺序扫描记录快100倍. 假设我们创建了一个名为people的表: CREATE TABLE people (

(转)Mysql 索引原理及优化

本文内容主要来源于互联网上主流文章,只是按照个人理解稍作整合,后面附有参考链接. 一.摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BTree索引,哈希索引,全文索引等等.为了避免混乱,本文将只关注于BTree索引,因为这是平常使用MySQL时主要打交道的索引,至于哈希索引和全文索引本文暂不讨论. 二.常见的查询算法及数据结构 为什么这里要讲查询算

Mysql索引分析:适合建索引?不适合建索引?【转】

数据库建立索引常用的规则如下: 1.表的主键.外键必须有索引: 2.数据量超过300的表应该有索引: 3.经常与其他表进行连接的表,在连接字段上应该建立索引: 4.经常出现在Where子句中的字段,特别是大表的字段,应该建立索引: 5.索引应该建在选择性高的字段上: 6.索引应该建在小字段上,对于大的文本字段甚至超长字段,不要建索引: 7.复合索引的建立需要进行仔细分析:尽量考虑用单字段索引代替: A.正确选择复合索引中的主列字段,一般是选择性较好的字段: B.复合索引的几个字段是否经常同时以A

MySQL索引原理及优化

一.各种数据结构介绍 这一小节结合哈希表.完全平衡二叉树.B树以及B+树的优缺点来介绍为什么选择B+树. 假如有这么一张表(表名:sanguo): (1)Hash索引 对name字段建立哈希索引: 根据name字段值进行hash计算,定位到数组的下标,因为字段值所对应的数组下标是哈希算法随机算出来的,所以可能出现哈希冲突.其中每一个节点存储的是name字段值及对应的行数据地址,那么对于这样一个索引结构,现在来执行下面的sql语句:  select * from sanguo where name

MySQL索引类型及优化

索引是快速搜索的关键.MySQL索引的建立对于MySQL的高效运行是很重要的.下面介绍几种常见的MySQL索引类型. 在数据库表中,对字段建立索引可以大大提高查询速度.假如我们创建了一个 mytable表: CREATE TABLE mytable( ID INT NOT NULL, username VARCHAR(16) NOT NULL ); 我们随机向里面插入了10000条记录,其中有一条:5555, admin. 在查找username="admin"的记录 SELECT *

mysql性能分析与优化

Hash索引的限制 Hash索引必须进行二次查找 Hash索引无法用于排序 Hash索引不支持部分索引查找,也不支持范围查找 Hash索引中Hash码的计算可能存在Hash冲突 为什么要使用索引 索引大大减少了存储引擎需要扫描的数据量 索引可以帮助我们进行排序以避免使用临时表 索引可以把随机I/O变为顺序I/O 索引优化策略 索引列上不能使用表达式或函数 前缀索引和索引列的选择性,索引的选择性是不重复的索引值和表的记录数的比值 联合索引 如何选择索引列的顺序 经常会被使用到的列优先 选择性高的列

MySQL性能分析和优化-part 1

MySQL性能优化 平时我们在使用MySQL的时候,怎么评估系统的运行状态,怎么快速定位系统瓶颈,又如何快速解决问题呢? 本文总结了多年来MySQL优化的经验,系统介绍MySQL优化的方法. OS性能分析 使用top观察top cpu/memory进程 使用mpstat观察每个CPU核心的CPU使用情况 使用iostat观察系统io状况 使用sar -n DEV观察网卡流量 使用vmstat查看系统内存使用情况 查看系统日志 使用dstat 记录和查看历史数据 查看昨天的数据 查看swap 查看

mysql 索引建立和优化

建立索引的几大原则 最左前缀匹配原则,mysql会一直向右匹配直到遇到范围查询(>.<.between.like)就停止匹配,比如a = 1 and b = 2 and c > 3 and d = 4 ,如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)的索引则都可以用到,a,b,d的顺序可以任意调整(参考原则2).但是mysql查询优化器可能通过优化调整顺序从而使用索引,但是写sql语句时还是按照此原则: = 和 in可以乱序,比如a = 1 and b

mysql索引原理及优化(二)

索引原理分析:数据结构 索引是最常见的慢查询优化方式其是一种优化查询的数据结构,MySql中的索引是用B+树实现,而B+树就是一种数据结构,可以优化查询速度,可以利用索引快速查找数据,优化查询. 可以提高查询速度的数据结构:哈希表.完全平衡二叉树.B树.B+树等等. 哈希:select* from sanguo where name>'周瑜     哈希表的特点是可以快速的精确查询,但是不支持范围查询.完全平衡二叉树:对于数据量大情况,它相比于哈希或者B树.B+树需要查找次数更多.B树:比完全平