Mysql高级(索引及优化)

1. 存储引擎

  1. 在创建表时,指定存储引擎

    create table 表名(
    	......
    )engine=innodb;
    
  2. 查看当前数据库支持的存储引擎:

    show engines;

  3. 存储引擎的特点

    • InnoDB
      • DML操作遵循ACID模型,支持事务
      • 行级锁,提高并发访问性能
      • 支持外键FOREIGN KEY约束,保证数据的完整性和正确性
    • MyISAM
      • 不支持事务,不支持外键
      • 支持表锁,不支持行锁
      • 访问速度快
    • Memory
      • 内存存放
      • hash索引
    • 区别
      Mysql高级(索引及优化)_第1张图片

2. 索引

索引:一种高效查询的数据结构

  • 优缺点:Mysql高级(索引及优化)_第2张图片

2.1 索引的结构

  • 二叉树、红黑树:Mysql高级(索引及优化)_第3张图片

  • B-Tree:

    Mysql高级(索引及优化)_第4张图片数据结构动画演示网站

  • B+Tree:所有的数据都会出现在叶子节点,并且叶子节点形成一个单向链表Mysql高级(索引及优化)_第5张图片
    MySQL索引数据结构对B+Tree进行了优化,在其基础上,增加了一个指向相邻叶子节点的链表指针,形成了带有顺序指针的B+Tree,提高区间访问的性能
    Mysql高级(索引及优化)_第6张图片

  • Hash索引Mysql高级(索引及优化)_第7张图片
    特点:

    1. Hash索引只能用于对等比较,不支持范围查询
    2. 无法利用索引完成排序操作
    3. 查询效率高,通常只需要一次检索就可以了,效率通常要高于B+Tree索引
  • 为什么InnoDB存储引擎选择使用B+Tree索引结构?

    1. 相对于二叉树,层级更少,搜索效率高
    2. 相对于B-Tree,无论叶子节点还是非叶子节点,都会保存数据,导致一页中存储的键值减少,指针跟着减少,要同样保存大量数据,只能增加树的高度,导致性能降低
    3. 相对于Hash索引,B+tree支持范围匹配和排序操作

2.2 索引的分类

  • 索引分类:
    Mysql高级(索引及优化)_第8张图片
    • 聚集索引选取规则:
      1. 主键索引为聚集索引
      2. 不存在主键,则将使用第一个唯一索引作为聚集索引
      3. 如果都没有,则会自动生成一个rowid作为隐藏的聚集索引
    • 聚集索引和二级索引
      Mysql高级(索引及优化)_第9张图片
      如:select * from user where name = 'Arm';因为name字段的索引属于二级索引,则先查找二级索引构成的b+树,找到对应的叶子节点,因为该节点下挂载的是id,而查询的是全部数据,所以根据挂载的id进行回表查询聚集索引构建的B+树
  • InnoDB 主键索引的B+Tree能存放多少行数据Mysql高级(索引及优化)_第10张图片

2.3 索引语法

  • 创建索引

    CREATE [UNIQUE | FULLTEXT] INDEX 索引名 ON 表名(字段1,字段2…)

  • 查看所有

    SHOW INDEX FROM 表名

  • 删除索引

    DROP INDEX 索引名 ON 表名

2.4 SQL 性能分析

2.4.1 SQL 执行频率

MySQL客户端连接成功后,通过 show [session|global] status命令可以提供服务器状态信息。通过如下指令,可以查看当前数据库的 增删改查的访问频率
> SHOW GLOBAL STATUS LIKE ‘Com_______’;

2.4.2 慢日志查询

慢查询日志记录了所有执行时间超过指定参数(long_query_time,单位:秒,默认10秒)的所有SQL语句的日志。
MySQL的慢查询日志默认没有开启,需要在配置文件 my.cnf中配置如下信息
Mysql高级(索引及优化)_第11张图片

查看慢查询日志的开启状态:show variables like ‘slow_query_log’;

2.4.3 profile 详情

show profiles 能够在做SQL优化时间帮助我们了解消费的时间,通过 have_profiling参数,能够查看当前MySQL是否支持profile操作

select @@have_profiling

默认profiling是关闭的,可以通过set语句在 session/global级别开启profiling

开启:set profiling = 1;
查看开启状态:select @@profiling;
Mysql高级(索引及优化)_第12张图片

2.4.4 执行计划

直接在select 语句前加上关键字 explain / desc

explain select 字段列表 from 表名 where 条件;
Mysql高级(索引及优化)_第13张图片

explain执行计划各字段含义:
Mysql高级(索引及优化)_第14张图片
Mysql高级(索引及优化)_第15张图片

2.5 索引使用

2.5.1 最左前缀法则

如果使用的是联合索引,要遵循最左前缀法则。查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃某一列,索引将部分失效(后面的字段索引失效)

假设user表存在联合索引(profession,age,status)
desc select * from user where profession = ‘软件’ and age = 31 and status=‘0’; 索引全部生效
desc select * from user where profession = ‘软件’ and age=31; status索引失效
desc select * from user where profession=‘软件’; age,status索引失效
desc select * from user where age=31 and status=‘0’;索引全部失效

2.5.2 索引失效

联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效,所以范围查询尽可能的使用 >= 而不是>,<

Mysql高级(索引及优化)_第16张图片

索引列运算

在索引列上进行运算操作,索引将会失效
> select * from user where substring(phone,10,2)=‘15’;索引失效

字符串不加引号

字符串类型字段使用时,不加引号,索引将失效
> desc select * from user where phone=‘11111111111’;索引生效
> desc select * from user where phone=‘11111111111’;索引失效

模糊查询,头部模糊匹配

如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引将失效
> select * from user where phone like ‘156%’;索引生效
select * from user where phone like ‘%6’; **索引失效 **

or 连接的条件

用 or 分割开的条件,必须两个条件中列都有索引,否则索引失效

数据分布影响

如果MySQL 评估使用索引比全表更慢,则不使用索引

select * from user where phone >= ‘17799999999’;使用索引
select * from user where phone >=‘17700000000’;不使用索引

SQL提示

SQL提示,是优化数据库的一个重要手段,简单来说就是在SQL语句中加入一些人为的提示来达到优化操作的目的

  • use index:使用该索引

    desc select * from user use index(idx_user_pro) where profession = ‘软件工程’;

  • ignore index:不使用该索引

    desc select * from user ignore index(idx_user_pro) where profession=‘软件工程’;

  • force index:必须使用该索引

    desc select * from user force index(idx_user_pro) where profession=‘软件工程’;

覆盖索引

尽量使用覆盖索引(查询使用了索引,并且需要返回的列,在该索引中能够全部找到),减少 select *
Mysql高级(索引及优化)_第17张图片
Mysql高级(索引及优化)_第18张图片

using index condition:查找使用了索引,但需回表查询数据
using where; using index:查询使用了索引,但需要的数据都在索引列中能找到,所以不需要回表查询数据

前缀索引

当字段类型为字符串(varchar,text等)时,有时候需要索引很长的字符串,这会让索引变得很大,查询时浪费了大量的磁盘io,影响查询效率,此时可以只将字符串的一部分前缀,建立索引,这样可以大大节约索引空间,提高索引效率

  • 语法:create index 索引名 on 表名(字段名(n));n为截取前面 n 个字符
  • 前缀长度:
    可以根据索引的选择性来决定,而选择性是值不重复的索引值(基数)和数据表的记录总数的比值,索引选择性越高查询效率越高,唯一索引的选择性是1,这是最好的索引选择性,性能也是最好的

2.6 索引设计原则

  1. 针对数据量较大,且查询比较频繁的表建立索引
  2. 针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立索引
  3. 尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高
  4. 如果是字符串类型的字段,字段长度越长,可以针对于字段的特点,建立前缀索引
  5. 尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间,避免回表,提高查询效率
  6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率
  7. 如果索引列不能存储null 值,在创建表使用 not null约束它,当优化器知道每列是否包含null值时,它可以更好的确定哪个索引最有效地用于查询

3. SQL优化

3.1 插入数据

  • insert 优化
    1. 批量插入
    2. 手动提交事务
    3. 主键顺序插入
  • 大批量插入数据
    如果一次性需要插入大批量数据,使用insert 插入性能较低,推荐使用 load 指令

3.2 主键优化

  • 主键设计原则
    1. 满足业务需求的同时,尽量降低主键的长度
    2. 插入数据时,尽量选择顺序插入,选择 AUTO_INCREMENT自增主键
    3. 尽量不要使用 UUID 做主键或者是其它自然主键,如身份证号
    4. 尽量避免对主键的修改

3.3 order by优化

  1. Using filesort:通过表的索引或全表扫描,读取满足条件的数据行,然后在排序缓冲区 sort buffer 中完成排序操作,所有不是通过索引直接返回排序结果的排序都叫 fileSort排序
  2. Using index:通过有序索引顺序扫描直接返回有序数据,这种情况即为 using index。不需要额外排序,操作效率高

创建索引时,指定索引的排序方式:
create index idx_user_age_phone on user(age desc,phone desc);

3.4 group by优化

  • 分组操作时,可以通过索引来提高效率
  • 索引的使用要满足最左前缀法则

3.5 limit优化

一个常见的问题:limit 2000000,10,此时需要MySQL排序前 200010 记录,仅仅返回2000000-2000010的记录,其它的记录丢弃,查询排序的代价非常大

  • 优化思路:一般分页查询时,通过创建 覆盖索引 能够较好的提高性能,可以通过覆盖索引急+子查询形式进行优化

select s.* from stu s,(select id from stu order by id limit 2000000,10) a where s.id = a.id;

3.6 count优化

select count(*) from user;

  • MyISAM 引擎把一个表的总行数存在了磁盘上,因此执行 count(*) 的时候直接返回这个数,效率很高
  • InnoDB 引擎执行 count(*) 的时候,需要把数据一行一行地从引擎中读出来,然后累加计数
  • count的几种用法及流程:
    1. count() 是一个聚合函数,对于返回的结果集,一行行地判断,如果 count 函数的参数不是 NULL ,累计值+1,最后返回累计值
    2. 用法:count(*)、count(主键)、count(字段)、count(1)
    3. 底层流程
      • count(主键):
        InnoDB 引擎会遍历整张表,把每一行的 主键id 值都取出来,返回给服务层,服务层拿到主键后,直接按行进行累加
      • count(字段):
        没有 not null 约束:InnoDB引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,服务层判断是否为null,不为null,计数累加
        有 not null 约束:InnoDB 引擎会遍历整张表把每一行的字段值都取出来,返回给服务层,直接按行累加
      • count(1)
        InnoDB 引擎遍历整张表,但不取值。服务层对于返回的每一行,放一个数字 “1” 进去,直接按行进行累加
      • count(*) 推荐
        不取值,服务层直接按行进行累加

3.7 update优化

更新的条件必须加索引,InnoDB的行锁是针对索引加的锁,不是针对记录加的锁,并且该索引不能失效 ,否则会从行锁升级为表锁

4. 锁

4.1 全局锁:锁定数据库中的所有表

加锁后整个实力就处于只读状态,使用场景:全库的逻辑备份

开启全局锁:flush tables with read lock;
关闭全局锁:unlock tables;

4.2 表级锁:每次操作锁住整张表

表级锁,每次操作锁住整张表,锁定力度大,发生锁冲突的概率最高,并发度最低。应用在MyISAM、InnoDB等存储引擎中

  • 语法:

    加锁:lock tables 表名… read/write
    释放锁:unlock tables 或 关闭客户端

  • 分类:
    1. 表锁

      • 表共享读锁(read lock):每个客户端只能读不能写
      • 表独占写锁(write lock):当前客户端能读写,其它客户端不能读写
    2. 元数据锁
      加锁过程是系统自动控制的,无需显示使用,在访问一张表的时候会自动加上
      主要作用:当表中存在未提交的事务时,不允许修改表结构,保持了元数据的数据一致性在这里插入图片描述

    3. 意向锁

4.3 行级锁:每次操作锁住对应行数据

5. InnoDB引擎

6. MySQL 管理

你可能感兴趣的:(mysql,数据库,database,java)