索引###

索引的概述

1. 概念:索引(index)是帮助数据库高效获取数据的数据结构,数据库系统维护查找数据的特定数据结构,这些数据结构指向我们的数据,通过高效算法实现高效查找。

2. 学习过的数据结构:

  • 链表

  • hash表

  • 二叉树

  • 红黑树

3. 无索引的查询

select * from emp where age = 19;
  • 无索引的情况下,需要全文检索,全表扫描,性能会很低。

 4. 有索引查询

select * from emp where age = 19;
  • 有索引,扫描特别快,时间复杂度极大降低,提高了查询速度

5. 优缺点  

优点缺点
提高了查询速度,降低数据库 io 的成本索引也需要维护,也需要占用空间
通过索引列对数据进行排序,降低排序成本,降低了CPU的消耗对于表的 INSERT,UPDATE,DELETE 效率降低

索引结构

1. 存储引擎层支持索引,也就是说不通的存储引擎可能支持不同的索引。

2. 数据引擎和索引结构之间的关系

3. 注意:没有特别说明,提问的数据索引都是 B+树索引

Hash 索引

1. 使用 Hash算法,将键值换算成hash 值,映射到对应的槽位上存储在hash 表中。

2. 特点:查询非常快

  • Hash 索引只支持对等比较(=,in),不支持范围查询(between,>,<)

  • 索引不支持排序

  • 如果没有hash 冲突的时候,查找一次就行了。比B+tree 索引还要快。

3. Mysql 支持 Hash 索引的就是 Memory,Innodb 支持hash 索引,是通过指定条件下自动构建。

二叉树

1. 注意:加入我们mysql 构建的二叉树数据结构索引,比较理想的就是平衡的二叉树。

2. 问题:

  • id的插入是自增的,此时二叉树变成了单向链表

  • 此时做查询时,会存在如下问题

    • 顺序插入的时候,会形成链表,查询性能很低。

    • 如果数据量很大的情况,层级会很深,查询速度会很慢。

  • 演示网址

红黑树

 1. 问题:

  • 红黑树还是一颗二叉树,会存在层级较深的问题,查询速度也会很慢

B-Tree

1. 多叉路平衡查找树,相对于每个二叉树,每个节点有多个分支(多叉)。

2. 度数:一个节点子节点的个数,一个最大度数为4(4级)的b-tree为例,每个节点只能存储3key,4个指针。

3. 特点  

  • 5阶B数,每一个节点最多有4个K,有5个指针。

  • 当存储元素达到key 的数量时,中间元素向上分裂。

  • 叶子节点和非叶子节点都会存放数据。

B+Tree

注意:  

  • 叶子节点存放数据,非叶子节点存放索引结构。

  • 叶子节点通过一个指针进行关联,编程了一个链表的结构

  • 当需要裂变的时候,非叶子节点的数据也会出现在叶子节点

  • 蓝色框的只存索引结构

注意:Mysql B+Tree 其实进行优化的,在原来的 B+Tree 的基础上,增加了一个指向相邻叶子节点的链表指针,就形成了带有顺序的指针B+Tree,提高区间访问性能。  

索引分类

  • 主键索引

  • 唯一索引

  • 常规索引

聚集索引与二级索引

1. 需求  

  • 查询步骤

    • 根据 name 去二级索引查询到具体的id=4

    • 根据得到的id=4去到聚集索引里面查找,最终拿到这一行的数据

select *from  emp where name = 'ez';

2. 注意:  

  • 数据关联在聚集索引子节点的

  • 二级索引只是关联聚集索引的id

  • 非聚集索引的查询都是通过回表查询查询出的数据

3. 聚集索引的选取规则:

  • 如果存在主键,选择主键作为聚集索引

  • 如果不存在主键,会去选择第一个唯一索引(UNIQUE)作为聚集索引。

  • 如果都没有,那么 Innodb 会默认生成一个 rowid 作为隐藏的聚集索引。

面试题

1. innodb 为什么选择 B+Tree 做为索引结构

  • 对于Hash 索引,Hash 索引不支持范围查询不支持排序

  • 对于二叉树索引,层级更多,搜索效率低

  • B-Tree 来说,无论是子节点,还是非叶子节点都存放数据,每一页的数据只有16K,如果非叶子节点存放数据了,那么每一页存储的数据就会变少,指针和键值都会变少

2. 分析sql 判断查询效率高低

  • id 是主键

  • name 建立了普通索引

A select * from emp where id = 3;

B select * from emp where name ='ez';
  • 答案:

    • A sql 查询速度高于B sql

    • Asql 直接使用聚集索引,可以直接返回 row 信息

    • Bsql 先使用二级索引去查找出id=3 然后再去通过聚集索引查找出 row,需要回表查询,所以效率低

3. Innodb 主键索引使用 B+Tree 能够存储多少数据?

  • 假设一行数据为1K,一页可以存储16行数据。Innodb 指针固定占用 6个字节,主键bigint 8,int 4

  • 高度为2

    • 16*1024 = x * 8 + (x+1)*6 x = 1170 指针就是 1171 *16

  • 高度为3

    • 1171*1171 * 16 =千万级的

索引语法

1. 查询索引  

SHOW INDEX FROM table_name ;

2. 创建

CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name ( index_col_name,... ) ;

 3. 删除索引

DROP INDEX index_name ON table_name ;

4. 通过sql 操作索引

  • 为用户名创建索引 
create index ix_user_name on user(user_name);
  •  给 phone 建立索引(唯一索引)
create unique  index  ix_phone on user(phone);
  • 给专业和年龄和状态建立联合索引
create index ix_p_age_s on user(profession,age,status);
  • 给专业建索引
create index ix_p on user(profession);
  • 查一下所有索引
show index from user;
  • 删除 ix_p 索引
drop index ix_p on user;

SQL性能分析

SQL执行频次

1. 语法:

SHOW GLOBAL STATUS LIKE 'COM_+类型';
COM_insert; 插入次数
com_delete; 删除次数
com_update; 更新次数
com_select; 查询次数
com_______;

2. 注意:通过语法,可以查询到数据库的实际状态,就可以知道数据库是以增删改为主,还是以查询为主,如果是以查询为主,就可以考虑sql 的索引优化。

慢查询日志

1. 概述:慢查询日志记录了超过指定时间的查询sql,指定参数(long_query_time,单位是秒,默认值是10秒)

2. 如何查看慢查询功能是否打开?

show variables like 'slow_query_log';

3. 参数说明  

4. 演示慢查询

5. 分析慢查询日志

  • slow-query-log=1 代表开启 =0 代表关闭

  • long_query_time=10 代表慢查询超过10秒日志会记录

  • slow_query_log_file 慢查询的日志文件

  • 把慢查询打开 slow-query-log=1

  • 把慢查询时间设置段 1秒 long_query_time=1

  • 重启一下mysql 的服务

  • 当sql 出现到慢查询日志中的时候,就可以考虑对这条sql 进行优化了。

Profile 详情

1. 概述:show profiles 能够用来做 SQL优化时协助我们了解时间消耗去哪里

2. 查看Profile 是否开启

select @@profiling;

 3. 设置Profile 开启

set [session/global] profiling=1

4. 通过 profile 了解时间的消耗

select * from user;

select count(*) from user;

select * from user where id = 10;

select * from user where name = '荆轲';
  • 使用profiles 文件观察时间消耗;

    • show profiles;(每次执行,query_id 都会变)

  • show proflie for query query_id;(注意 query_id 是使用 show profiles 查询出来的)  

  • show profile cpu for query query_id  

explain

1. explain 或者 desc 都可以去获取 mysql 执行 select 语句的信息,包含索引选用、连接表等信息;

2. 语法:

  • 演示 id 执行先后的  
explain select * from emp where dept_id = (select id from dept where name = '研发部')
  • 演示 type(const 使用主键或者唯一索引的时候)
explain select id from dept where name = '研发部'; all

explain select * from emp where id = 1;

explain select * from user where phone = '13508895543'

  • key 演示
explain select * from user where id  > 5

索引的使用

1. 索引效率验证

  • 添加主键索引(添加的时候,需要维护索引数据,所以速度较慢)

    • 没有主键索引的时候耗时情况

  •  添加了主键索引的时候耗时情况

  • 给 name 字段添加索引列

    • name 没有添加索引列的时候  

  • 给name 添加了索引列之后  

2. 结论:索引确实能提升查询速度,而且是质的提升。

最左前缀法则

1. 最左前缀法则适用于联合索引;查询从索引的最左列开始,不跳过其中的列,如果跳过其中的列将会导致索引失效(后面字段的索引失效)。

2. 验证最左前缀法则

  • 三个列的联合索引都同时使用

  • 只使用专业和年龄查询  
explain select * from user where profession = '通讯工程' and age = 17;

  • 只使用专业和年龄查询  
explain select * from user where profession = '通讯工程' and age = 17;

  • 只使用专业查询  
explain select * from user where profession = '通讯工程';

3. 最左原则使用索引的情况(A+B+C)

  • A

  • AB

  • ABC

  • BC(X)

  • AC(使用A索引)

  • CBA

索引失效

1. 字符串不加引号

explain select *from user where phone = 13708822169;

 2. or 连接(or 前后没有建立索引的时候不会被用到)

explain select *from user where phone = 13708822169 or status = 0;

3. 模糊查询  

explain select * from user where phone like '%0' ;

4. 对于索引使用函数运算  

explain select * from user where substring(phone,1,2) = '19' ;

5. 数据分布影响  

explain select * from user where phone > '13508822168';

explain select * from user where gender = 1;

索引的使用和设计原则

使用原则

1. 避免使用 select * from table_name;

  • 可能避免了回表查询(减少一次查询,提高了效率,前提是查询的结果已经再二级索引的叶子节点出现)

2. 使用前缀索引代替全索引

  • 计算前缀长度(唯一索引的性能是最高的,唯一索引的前缀长度是1)

  • 不重复的索引基数/数据表的总记录数

select count(*) from user;

select count(distinct email) from user;

select count(distinct substring(email ,1,8)) from user;

select count(distinct substring(email ,1,2))/count(*) from user;

3. 单列索引和联合索引

  • 使用多个单列索引查询时,并不会全用索引,会根据mysql优化器的指引进行选择

设计原则

1. 数据量大的时候,一定要建索引

2.针对于经常查询的多列,去建联合索引

3.如果是字符串类型,而且数据很大,尽量去使用前缀索引,前缀度我们尽量去靠近1

4. 索引还需要控制数量,索引不是越多越好,一定要合适就行,越多增删改越慢,影响用户体验

5. 要去选择区分度高的列做索引,尽量去建立唯一索引

6. 设计列尽量不要去存空数据

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值