MYSQL——索引原理与慢查询优化

一、索引原理与慢查询优化

  ps:数据都是存在与硬盘上的,查询数据不可避免的需要进行IO操作

  1、 索引:就是一种数据结构,类似于书的目录。意味着以后在查询数据的应该先找目录再找数据,而不是一页一页的翻书,从而提升查询速度降低IO操作

  2、索引在MySQL中也叫“键”,是存储引擎用于快速查找记录的一种数据结构

    * primary key
    * unique key
    * index key

  注意 : foreign key不是用来加速查询用的,不在我们的而研究范围之内

上面的三种key,前面两种除了可以增加查询速度之外各自还具有约束条件,而最后一种index key没有任何的约束条件,只是用来帮助你快速查询数据

3、本质

  通过不断的缩小想要的数据范围筛选出最终的结果,同时将随机事件(一页一页的翻)
 变成顺序事件(先找目录、再找数据)
 也就是说有了索引机制,我们可以总是用一种固定的方式查找数据
 4、一张表中可以有多个索引(多个目录)

 5、 索引虽然能够帮助你加快查询速度但是也有缺点

   1 当表中有大量数据存在的前提下 创建索引速度会很慢
   2 在索引创建完毕之后 对表的查询性能会大幅度的提升 但是写的性能也会大幅度的降低

   ps:索引不要随意的创建!!!

6、b+树

为什么说B+树比B树更适合做操作系统的数据库索引和文件索引?

(1)B+树的磁盘读写的代价更低

B+树内部结点没有指向关键字具体信息的指针,这样内部结点相对B树更小。

(2)B+树的查询更加的稳定

因为非终端结点并不是最终指向文件内容的结点,仅仅是作为叶子结点中关键字的索引。这样所有的关键字的查找都会走一条从根结点到叶子结点的路径。所有的关键字查询长度都是相同的,查询效率相当。
### b+树

  """
  只有叶子节点存放的是真实的数据 其他节点存放的是虚拟数据 仅仅是用来指路的
  树的层级越高查询数据所需要经历的步骤就越多(树有几层查询数据就需要几步),所以要想查询快,树的层数越少越好
  
  一个磁盘块存储是有限制的
  为什么建议你将id字段作为索引
      占得空间少 一个磁盘块能够存储的数据多
      那么久降低了树的高度 从而减少查询次数
  """
 

  ### 聚集索引(primary key)

  """
  聚集索引指的就是主键 
  Innodb  只有两个文件  直接将主键存放在了idb表中 
  MyIsam  三个文件  单独将索引存在一个文件
 叶子节点放的是一条条完整的数据 """ ### 辅助索引(unique,index) 查询数据的时候不可能一直使用到主键,也有可能会用到name,password等其他字段 那么这个时候你是没有办法利用聚集索引。这个时候你就可以根据情况给其他字段设置辅助索引(也是一个b+树) """ 叶子节点存放的是数据对应的主键值 先按照辅助索引拿到数据的主键值 之后还是需要去主键的聚集索引里面查询数据 """ ### 覆盖索引 在辅助索引的叶子节点就已经拿到了需要的数据 # 给name设置辅助索引 select name from user where name='jason'; # 非覆盖索引 select age from user where name='jason';

7、测试索引是否有效的代码

 #1. 准备表
  create table s1(
  id int,
  name varchar(20),
  gender char(6),
  email varchar(50)
  );
  
  #2. 创建存储过程,实现批量插入记录
  delimiter $$ #声明存储过程的结束符号为$$
  create procedure auto_insert1()
  BEGIN
      declare i int default 1;
      while(i<3000000)do
          insert into s1 values(i,'jason','male',concat('jason',i,'@oldboy'));
          set i=i+1;
      end while;
  END$$ #$$结束
  delimiter ; #重新声明分号为结束符号
  
  #3. 查看存储过程
  show create procedure auto_insert1G 
  
  #4. 调用存储过程
  call auto_insert1();
  ​```
  
  ​``` mysql 
  # 表没有任何索引的情况下
  select * from s1 where id=30000;
  # 避免打印带来的时间损耗
  select count(id) from s1 where id = 30000;
  select count(id) from s1 where id = 1;
  
  # 给id做一个主键
  alter table s1 add primary key(id);  # 速度很慢
  
  select count(id) from s1 where id = 1;  # 速度相较于未建索引之前两者差着数量级
  select count(id) from s1 where name = 'jason'  # 速度仍然很慢
  
  
  """
  范围问题
  """
  # 并不是加了索引,以后查询的时候按照这个字段速度就一定快   
  select count(id) from s1 where id > 1;  # 速度相较于id = 1慢了很多
  select count(id) from s1 where id >1 and id < 3;
  select count(id) from s1 where id > 1 and id < 10000;
  select count(id) from s1 where id != 3;
  
  alter table s1 drop primary key;  # 删除主键 单独再来研究name字段
  select count(id) from s1 where name = 'jason';  # 又慢了
  
  create index idx_name on s1(name);  # 给s1表的name字段创建索引
  select count(id) from s1 where name = 'jason'  # 仍然很慢!!!
  """
  再来看b+树的原理,数据需要区分度比较高,而我们这张表全是jason,根本无法区分
  那这个树其实就建成了“一根棍子”
  """
  select count(id) from s1 where name = 'xxx';  
  # 这个会很快,我就是一根棍,第一个不匹配直接不需要再往下走了
  select count(id) from s1 where name like 'xxx';
  select count(id) from s1 where name like 'xxx%';
  select count(id) from s1 where name like '%xxx';  # 慢 最左匹配特性
  
  # 区分度低的字段不能建索引
  drop index idx_name on s1;
  
  # 给id字段建普通的索引
  create index idx_id on s1(id);
  select count(id) from s1 where id = 3;  # 快了
  select count(id) from s1 where id*12 = 3;  # 慢了  索引的字段一定不要参与计算
  
  drop index idx_id on s1;
  select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx';
  # 针对上面这种连续多个and的操作,mysql会从左到右先找区分度比较高的索引字段,先将整体范围降下来再去比较其他条件
  create index idx_name on s1(name);
  select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx';  # 并没有加速
  
  drop index idx_name on s1;
  # 给name,gender这种区分度不高的字段加上索引并不难加快查询速度
  
  create index idx_id on s1(id);
  select count(id) from s1 where name='jason' and gender = 'male' and id = 3 and email = 'xxx';  # 快了  先通过id已经讲数据快速锁定成了一条了
  select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  # 慢了  基于id查出来的数据仍然很多,然后还要去比较其他字段
  
  drop index idx_id on s1
  
  create index idx_email on s1(email);
  select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  # 快 通过email字段一剑封喉 
#### 联合索引

  select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  
  # 如果上述四个字段区分度都很高,那给谁建都能加速查询
  # 给email加然而不用email字段
  select count(id) from s1 where name='jason' and gender = 'male' and id > 3; 
  # 给name加然而不用name字段
  select count(id) from s1 where gender = 'male' and id > 3; 
  # 给gender加然而不用gender字段
  select count(id) from s1 where id > 3; 
  
  # 带来的问题是所有的字段都建了索引然而都没有用到,还需要花费四次建立的时间
  create index idx_all on s1(email,name,gender,id);  # 最左匹配原则,区分度高的往左放
  select count(id) from s1 where name='jason' and gender = 'male' and id > 3 and email = 'xxx';  # 速度变快

8、查询优化神器-explain

执行计划:让mysql预估执行操作(一般正确)
    all < index < range < index_merge < ref_or_null < ref < eq_ref < system/const
    id,email
    
    慢:
        select * from userinfo3 where name='alex'
        
        explain select * from userinfo3 where name='alex'
        type: ALL(全表扫描)
            select * from userinfo3 limit 1;
    快:
        select * from userinfo3 where email='alex'
        type: const(走索引)

9、慢查询优化的基本步骤

0.先运行看看是否真的很慢,注意设置SQL_NO_CACHE
1.where条件单表查,锁定最小返回记录表。这句话的意思是把查询语句的where都应用到表中返回的记录数最小的表开始查起,单表每个字段分别查询,看哪个字段的区分度最高
2.explain查看执行计划,是否与1预期一致(从锁定记录较少的表开始查询)
3.order by limit 形式的sql语句让排序的表优先查
4.了解业务方使用场景
5.加索引时参照建索引的几大原则
6.观察结果,不符合预期继续从0分析

10、慢日志管理

慢日志
            - 执行时间 > 10
            - 未命中索引
            - 日志文件路径
            
        配置:
            - 内存
                show variables like '%query%';
                show variables like '%queries%';
                set global 变量名 = 值
            - 配置文件
                mysqld --defaults-file='E:wupeiqimysql-5.7.16-winx64mysql-5.7.16-winx64my-default.ini'
                
                my.conf内容:
                    slow_query_log = ON
                    slow_query_log_file = D:/....
                    
                注意:修改配置文件之后,需要重启服务

一、

二、

三、

四、

五、

原文地址:https://www.cnblogs.com/guojieying/p/13644449.html