Mysql索引

7、索引

概念:索引index是帮助MYSQL高效获取数据的数据结构。索引是数据结构(树) MYSQL里的索引是B+树

索引类似于书的目录

SQL优化的原因:性能低,执行时间长,等待时间长,sql语句欠佳(连接查询)、索引失效、服务器参数设置不周

SQL编写过程:

select .. from  .. join ... on ..where  ..group by ... having...order by...limit..

解析过程

先解析 from.... on  .. join...where ..group by ...having ..select ..order by  limit

索引的底层原理B+树

三层B+树,一个关键字对应一个指针,对应一个指数

B+树的数据全部存放在叶节点中,

B+树中查询任意的数据次数:n次(B+树的高度)

7.1、索引分类

  1. 单列索引

    • 主键索引(PRIMARY KEY)

      ​ 唯一的标识,主键不可重复

    • 唯一索引 (UNIQUE KEY/index)

      ​ 避免出现重复的列,可以重复,多个列都可以标识位 唯一索引

      人们创建唯一索引的目的往往不是为了提高访问速度,而只是为了避免数据出现重复

  2. 常规索引 (KEY/INDEX)

    • 默认的,index。key关键字来设置
  3. 全文索引 (FullText)

    • 快速定位数据
  4. 复合索引(组合索引)

    • 多个列构成的索引(相当于二级目录: z :zhao) 比如 先找 name列 再找 age,(name,age)不一定要都查询,只有重复的情况下才需要,复合索引可以有多个列

创建索引

  1. CREATE 索引类型 索引名 on 表名(字段)
---创建复合索引

-----【方式一】
create index  dept_index on tb(dept,name)
--tb(dept,name) 会自动生成符合索引


----【方式二】

alter table 表名 索引类型 索引名(字段)

alter table tablename  add unique index_name(name)

删除索引

drop index 索引名 on 表名


show index from 表名 \G

7.2、索引使用原则

索引的弊端
  • 索引不是越多越好,不要对经常变动的数据加索引
  • 小数据量的数据不要加索引
  • 很少使用的字段也不建议加索引
  • 索引虽然可以提高查询的效率,但是会降低增删改的效率
索引的优点
  • 提高查询效率(降低IO使用率)
  • 降低CPU使用率

7.3、SQL性能问题

  • 分析SQL的执行计划 : explain , 可以模拟SQL 优化器执行SQL语句
  • MySQL查询优化其会干扰我们的优化【mysql有一个查询优化器】

查询执行计划

explain + sql语句
mysql> explain select * from linelock \G
*************************** 1. row ***************************
           id: 编号
  select_type: 查询类型
        table: 表名
   partitions: NULL
         type: 类型
possible_keys: 预测用到的索引,可能用到索引的列都会列出来
          key: 实际使用的索引
      key_len:用于处理查询的索引长度,如果是单列索引,那就整个索引长度算进去,如果是多列索引,那么查询不				 一定都能使用到所有的列,具体使用到了多少个列的索引,这里就会计算进去,没有使用到的列,这里				不会计算进去
          ref: 表之间的引用
         rows: 执行计划中估算的扫描行数,不是精确值
     filtered: 100.00 这个字段表示存储引擎返回的数据在server层过滤后,剩下多少满足查询的记录数量的比                例,注意是百分比,不是具体记录数。  
        Extra: 额外的信息
1 row in set, 1 warning (0.00 sec)


----type:索引类型、类型
---system>const>eq_ref>ref>range>index>all,
---对type进行优化的前提:有索引
----system、const只是理想情况,实际能达到ref>range

ref:非位移性索引,对于每个索引建的查询,返回匹配的所有行(0,多)
range:检索指定范围的行,where后面是一个范围查询(between , > ,< = )

index:查询全部索引中的数据
all:查询全部表中的数据


system/const:结果只有一条数据
eq_ref:结果多条;但是每条数据是唯一的;
ref:结果多条;但是每条数据是0或多条



SQL

create table course (
    -> cid int(3),
    -> cname varchar(20),
    -> tid int(3)
    -> );


create table teacher(
    -> tid int(3),
    -> tname varchar(20),
    -> tcid int(3)
    -> );

create table teacherCard(
    -> tcid int(3),
    -> tcdesc varchar(200)
    -> );

---数据插入
insert into course values(1,'java',1),(2,'html',1),(3,'sql',2),(4,'jin',3);


insert into teacher values(1,'tz',1),(2,'tw',2),(3,'tl',3);

insert into teacherCard values(1,'tzdesc'),(2,'twdesc'),(3,'tldesc');

explain select t.* from teacher t,course c,teacherCard tc where t.tid=c.tid and t.tcid=tc.tcid and (c.cid=2 or tc.tcid=3);
------id值相同的情况下
----数据小的表优先计算,联立表查询时




----id值不同的时候
----id值越大越优先查询


select_type:
PRIMARY:包含子查询SQL中的 主查询(最外层)
SUBQUERY:包含子查询SQL中的子查询(非最外层)
simple:简单查询(不包含子查询、union)
derived:衍生查询(使用到了临时表)
 ------a、在from子查询中只有一张表
 ------b、在from子查询中,如果有table1 union table2,则table1就是derived
 
 
 ---ref:注意与type中的ref值区分
 --作用:知名当前表所参照的字段
 

 
---在utf-8中一个【字符】占【三个字节】
----如果索引字段可以为Nul,则会使用一个字节用于标识

{{
----etra字段
----【using filesort】:性能消耗大;需要额外的一次排序(查询),一般出现在order by中

---对于单索引,如果排序和查找的是同一个字段,则不会出现using filesort;如果不一样则会出现
---对于符合索引:不能跨列(最佳左前缀)


-----【using temporary】:性能损耗较大,用到了临时表,一般出现在group by中
----解决方法:查什么用什么分组


---【using index】:性能提升,索引覆盖
---表示:不读取源文件,只从索引字段开始查询,即不需要回表查询

---只要使用到的列,全部在索引中,那么就会有using index
---using index会对possible_key 和key造成影响
--1、如果没有where,则索引只出现在key中
--2、如果有where,则索引出现在key和possible_keys中

---【using where】(需要会表查询)
	--假设age是索引列,name不是
	--但查询语句中有 select age ,name from 。。 where age=。。 此语句必须回原表查name
	
---【impossible where】:where子句永远为false
}}


7.4、优化案例

单表优化、两表优化、多表优化

7.4.1、单表优化

create table book(
bid int(4) primary key,
name varchar(20) not null,
authorid int(4) not null,
publicid int(4) not null,
typeid int(4) not null
);

insert into book values(1,'java',1,1,2),(2,'fc',2,1,2),(3,'gf',3,2,1),(4,'magh',4,2,3);

1、问题:查询authorid=1且typeid为2或3的 bid

select bid from book where typeid in(2,3) and authorid =1 ;
explain select bid from book where typeid in(2,3) and authorid =1 ;   

优化:加索引

alter table book add index idx_bta(bid,typeid,authorid);

根据sql实际解析的顺序,调整索引的顺序

一旦进行索引升级优化,先前的索引应该删除,防止干扰

drop index idx_bta on book

索引升级

alter table book add index idx_tab(typeid,authorid,bid);
---虽然可以回表查询bid,但是可以将bid放在索引中,提高查找效率

索引再次优化

------思路:因为范围查询in有时会实现,因此交换索引的顺序,将typeid
alter index idx_tab on book;
alter table book add index idx_atb(authorid,typeid,bid);

explain select bid from book where  authorid =1 and typeid in(2,3) order by typeid desc;

小结:

  • 索引不能跨列使(最佳左前缀),保持索引的定义和使用的顺序一致性

  • 索引需要逐步优化

  • 将含in的范围查询放到最后,防止索引失效

  • using where 需要回原表查询,using index不需要回原表查询

7.5、避免索引失效的原则

  • 复合索引,不要跨列或者无序使用(最佳左前缀)
  • 尽量使用全索引匹配
    • 建了(a,b,c)三个索引,那么查询的时候尽量全用上
  • 不要在索引上进行任何操作(计算、函数、类型转换),否则索引失效
    • 例如: select 。。。where A.x = 。。。;假设A.x是索引,那么不要进行
    • select 。。。where A.x*3 = 。。。会索引失效
  • 对于复合索引(a,b,c) a失效了,b,c均失效
  • 符合索引不能使用不等于(!= <>)或is null (is not null),否则自身以及右侧所有全部失效

SQL优化是一种概率层面的优化。至于是否实际使用了我们的优化,需要通过explain进行推测

体验概率情况:原因是服务层中间有一层sql优化器,可能会影响我们的优化

  • like尽量以“常量”开头,不要以’%‘开头,否则索引失效

    select * from use where name ='%x%';---name索引失效
    
    --如果必须使用'%x%'进行模糊查询
    --则使用索引覆盖,可以挽救一部分
    select  tname from ta where tname like '%x%';
    
  • 尽量不要使用类型转换(显示、隐式),不然会索引失效

  • 尽量不要使用or,否则索引失效

7.5.2、一些其他的优化方法(刨除索引)

  • exist和in

    如果主查询的数据集大,则使用In

    如果子查询的数据集大,则使用exist

    exist语法:

    select tname from teacher where exist(sleect * from teacher)

    ---将主查询的结果,放到子查询中进行条件检验【是否有数据】,如果符合校验,则保留数据
  • order by 优化
    • using filesort 有两种算法:双路排序、单路排序(根据IO的次数)
    • MySQL4.1之前默认使用双路排序;双路:扫描两次磁盘(1:从磁盘读取排序字段,进行排序 (buffer中执行) 2:扫描其他字段)
    • MySQL4.1之后默认使用单路排序:只读取一次全部的字段,在buffer中进行排序。但是单路排序会有一定的隐患(不一定的真的是一次。)如果数据很大,可以考虑调大buffer容量的大小:set max_length_for_sort_data
    • 如果max_length_for_sort_data太低,mysql会自动切换到双路。
    • 避免使用 select * …

7.6、SQL排序-慢查询

mysql提供的一种日志记录,用于记录MySQL中相应时间超过阈值的SQL语句(long_query_time,默认10s)

慢查询日志默认关闭,开发调优是可以开启,如果最终部署时候要进行关闭。

检查是否开启了慢查询日志

show variables like '%slow_query_log%';

开启慢查询日志

  • 临时开启

    set global slow_query_log =1;   ----在内存中开启
    
  • 永久开启

/etc/my.cnf 中追加
  • 慢查询阈值:
show variables like '%long_query_time%'
  • 临时设置阈值:

    set globale long_query_time=5   ---要重新启动mysql生效
    
  • 查询超过阈值的SQL:

    show global status like '%slow_queries%';
    
    --慢查询的sql被记录在了日志中,可以通过日志查看具体的慢SQL
    --也可以通过mysql工具 查看  【mysqldumpslow】
    --通过 mysqldumpslow --help 来查看
    
  • 慢sql工具查看

    --获取返回记录组最多的3个SQL
    mysqldumpslow -s r -t 3  日志文件的路径
    
    

7.7、全局日志查询

全局查询日志:记录开启后的全部sql语句

show variables like '%general_log';

set global general_log=1; --开启全局日志
set global log_output='table';

--开启全局日志后,所有的记录都会被存储在mysql.general_log中
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值