• MySQL索引原理


    索引类型

    MySQL索引类型可以按不同纬度分为如下几种:

    • 从索引存储结构划分:B Tree索引、Hash索引、FULLTEXT全文索引、R Tree索引
    • 从应用层次划分:普通索引、唯一索引、主键索引、复合索引
    • 从索引键值类型划分:主键索引、辅助索引(二级索引)
    • 从数据存储和索引键值逻辑关系划分:聚集索引和非聚集索引
    1. 普通索引

    指基于普通字段建立的索引。建立索引的方法如下:

    CREATE INDEX <索引的名字> ON tablename (字段名);
    ALTER TABLE tablename ADD INDEX [索引的名字] (字段名);
    CREATE TABLE tablename ( [...], INDEX [索引的名字] (字段名) );
    
    1. 唯一索引

    与“普通索引”类似,不同的是:索引字段的值必须唯一,但允许有空值。在创建或修改表时追加唯一约束,就会自动创建对应的唯一索引。

    创建唯一索引的方法如下:

    CREATE UNIQUE INDEX <索引的名字> ON tablename (字段名);
    ALTER TABLE tablename ADD UNIQUE INDEX [索引的名字] (字段名);
    CREATE TABLE tablename ( [...], UNIQUE [索引的名字] (字段名) ;
    
    1. 主键索引

    它是一种特殊的唯一索引,不允许有空值。在创建或修改表时追加主键约束即可,每个表只能有一个主键。

    创建主键索引的方法如下:

    CREATE TABLE tablename ( [...], PRIMARY KEY (字段名) );
    ALTER TABLE tablename ADD PRIMARY KEY (字段名);
    
    1. 复合索引

    单一索引是指索引列为一列的情况,即新建索引的语句只实施在一列上;用户可以在多个列上建立索引,这种索引叫做组复合索引(组合索引)。复合索引可以代替多个单一索引,相比多个单一索引复合索引所需的开销更小。

    创建组合索引的方法如下:

    CREATE INDEX <索引的名字> ON tablename (字段名1,字段名2...);
    ALTER TABLE tablename ADD INDEX [索引的名字] (字段名1,字段名2...);
    CREATE TABLE tablename ( [...], INDEX [索引的名字] (字段名1,字段名2...) );
    

    复合索引使用注意事项:

    • 何时使用复合索引,要根据where条件建索引,注意不要过多使用索引,过多使用会对更新操作效率有很大影响。
    • 如果表已经建立了(col1,col2),就没有必要再单独建立(col1);如果现在有(col1)索引,如果查询需要col1和col2条件,可以建立(col1,col2)复合索引,对于查询有一定提高。
    1. 全文索引

    查询操作在数据量比较少时,可以使用like模糊查询,但是对于大量的文本数据检索,效率很低。如果使用全文索引,查询速度会比like快很多倍。在MySQL 5.6 以前的版本,只有MyISAM存储引擎支持全文索引,从MySQL5.6开始MyISAM和InnoDB存储引擎均支持。

    创建全文索引的方法如下:

    CREATE FULLTEXT INDEX <索引的名字> ON tablename (字段名);
    ALTER TABLE tablename ADD FULLTEXT [索引的名字] (字段名);
    CREATE TABLE tablename ( [...], FULLTEXT KEY [索引的名字] (字段名) ;
    

    和常用的like模糊查询不同,全文索引有自己的语法格式,使用 match 和 against 关键字,比如

    select * from user
    where match(name) against('aaa');
    

    索引原理

    MySQL官方对索引定义:存储引擎用于快速查找记录的一种数据结构,需要额外开辟空间和数据维护工作。

    • 索引是物理数据页存储,在数据文件中,利用数据页(page)存储
    • 索引可以加快索引速度,但是同时也会降低增删改操作速度,索引维护需要代价。

    索引涉及的理论知识:二分查找法、Hash、B+Tree

    1. 二分查找法

    二分查找法也叫做折半查找法,它是在有序数组中查找指定数据的搜索算法。他的优点是等值查询、范围查询性能好,缺点是更新数据、新增数据、删除数据维护成本高。

    查找步骤:

    • 首先定位left和right两个指针
    • 计算(left+right)/2,除不尽向下取余。并记为m
    • 判断除2后索引位置值与目标值的大小比对
    • 索引位置值大于目标值,right移动(right=m-1);如果小于目标值,left移动(left=m+1)

    举例:下面的有序数组有17个值,查找的目标值是7


    ......
    依次类推,直到索引位置值=查找的目标值
    2. Hash

    Hash底层实现是由Hash表来实现的,是根据键值<key,value>存储数据的结构

    1. B+Tree结构

    我们先来看看B树和B+树结构:

    • B Tree结构

    • 索引值和data数据分布在整棵树结构中
    • 每个节点可以存放多个索引值及对应的data数据
    • 树节点中的多个索引值从左到右升序排列

    B树的搜索:从根节点开始,对节点内的索引值序列采用二分法查找,如果命中就结束查找。没有命中会进入子节点重复查找过程,直到所对应的节点点指针为空,或已经是叶子节点了才结束。

    • B+Tree结构

    • 非叶子节点不存储data数据,只存储索引值,这样便于存储更多的索引值
    • 叶子节点包含了所有的索引值和data数据
    • 叶子节点用指针连接,提高范围查询性能

    B+树范围查询时,只需要查找定位两个节点的索引值,然后利用叶子节点的指针遍历即可。而B树需要遍历范围内所有的节点和数据。

    聚簇索引、辅助索引、非聚簇索引

    Mysql的索引普遍使用B+树做索引。

    聚簇索引和非聚簇索引:B+Tree的叶子节点存放主键索引值和行记录就属于聚簇索引;索引值和行记录分开存放就属于非聚簇索引

    主键索引和辅助索引:B+Tree的叶子节点存放的是主键字段就属于主键索引;存放的是非主键就属于辅助索引(也叫二级索引)


    InnoDB里的索引:

    聚簇索引:

    InnoDB的聚簇索引是按照主键顺序构建B+Tree结构。B+Tree的叶子节点就是行记录,行记录和主键值存在一块的。也就意味着InnoDB的主键索引就是数据表本身,它按照主键顺序存放了整张表的数据。通常来说主键索引就是聚簇索引。

    辅助索引:

    InnoDB辅助索引,是根据普通索引列构建B+Tree结构。在B+Tree叶子节点中只存了索引列和主键的信息。二级索引占用的空间会比聚簇索引小很多,但查询需要进行两遍检索,先从辅助索引处获得主键,然后再用主键去主键索引里获得行记录。


    MyISAM里的索引:

    非聚簇索引:

    MyISAM数据表的索引文件和数据文件是分开的,它的索引文件保存的不是完整的数据记录而是数据记录的地址。在MyISAM中,主键索引和辅助索引在结构上没有任何区别,只是主索引要求key是唯一的,而辅助索引的key可以重复

    索引分析和优化

    1. Expain的使用

    1. id列
      id代表有几条查询,有几条就有几个id,id越大越先执行,id相等则从上到下执行

    2. select_type 查询类型

    - simple:简单查询
    - primary:复杂查询最外层的select
    - subquery:包含在select中的子查询
    - derived:包含着from子句中的子查询。Mysql会将结果存在一个临时表(也叫派生表)中。
    - union:在union中的第二个和随后的sselect
    - union select:从union的临时表检索结果的select
    
    1. type

    表示关联类型或访问类型,即决定如何查找表中的行

    从优到差分别是:ststem > const > eq_ref > ref > range > index > ALL

    一般来说,保证达到range,最好达到ref

    system,const:一般就是只有一条记录,可以用常量代替的

    eq_ref:使用的索引是主键索引或唯一索引

    ref:使用的是普通索引

    range:范围扫描通常出现在in(),bewteen,>,<,=

    index:扫描全表索引,通常比ALL快一点

    ALL:扫描全表
    4. key

    会用到的索引

    1. possible_key 可能会用到的索引

    2. key_len

    索引长度,不同的类型长度计算方式不同

    1. rows

    可能会扫描到的行数
    8. Extra

    额外信息。有以下情况

    • Using index时,意思为覆盖索引,即能在索引中拿到数据,而不用在通过索引去查数据。
    • Using Where:查询的列未被索引覆盖
    • Using where Useing index:查询的列被索引覆盖,并且where筛选的条件是索引列之一,但不是前导列
    • Using temporary:查询的时候使用了临时表
    • Using filesort:文件排序

    最佳实践

    1. 全值匹配

    如果用了联合索引,那么最好所有的值都使用上。比如某个表有一个3个字段组成的联合索引,那么查询时where里面这三个都带上
    2. 索引最左前缀原理

    建立的联合索引的顺序是什么样,使用时就要什么样。(虽然你不按照顺序写,但优化器可能会优化)
    3. 不要在索引上做任何操作计算,函数,类型转换等
    4. Mysql使用!=或<>, isnull,is not null,会导致全表扫描
    5. like查询时,name like '%admi' 不走索引, name like 'adm%' 会走索引
    6. 字符串不加单引号索引失效
    7. 少用or或in,用他连接时索引可能会失效,跟数据量有关
    8. in和exists的区别

    //当A表数据大于B表时,in优于exists
    select * from A where id in(select id from B)
    
    1. 索引与排序

    MySQL查询支持filesort和index两种方式的排序,filesort是先把结果查出,然后在缓存或磁盘进行排序操作,效率较低。使用index是指利用索引自动实现排序,不需另做排序操作,效率比较高。

    以下两种情况用index的方式排序:

    • ORDER BY 子句索引列组合满足索引最左前列
    explain select id from user order by id; //对应(id)、(id,name)索引有效
    
    • WHERE子句+ORDER BY子句索引列组合满足索引最左前列
    explain select id from user where age=18 order by name; //对应
    (age,name)索引
    

    以下几种情况,会使用filesort方式的排序:

    • 对索引列同时使用了ASC和DESC
    explain select id from user order by age asc,name desc; //对应
    (age,name)索引
    
    • WHERE子句和ORDER BY子句满足最左前缀,但where子句使用了范围查询(例如>、<、in
      等)
    explain select id from user where age>10 order by name; //对应
    (age,name)索引
    
    • ORDER BY或者WHERE+ORDER BY索引列没有满足索引最左前列
    explain select id from user order by name;  //对应(age,name)索引
    
    • 使用了不同的索引,MySQL每次只采用一个索引,ORDER BY涉及了两个索引
    explain select id from user order by name,age; //对应(name)、(age)两个索
    引
    
    • WHERE子句与ORDER BY子句,使用了不同的索引
    explain select id from user where name='tom' order by age; //对应
    (name)、(age)索引
    

    2. 慢查询日志

    1. 开启慢查询日志

    查询慢日志是否开启和文件位置的命令:

    SHOW VARIABLES LIKE 'slow_query_log%'
    

    开启慢查询日志命令:

    SET global slow_query_log = ON;
    SET global slow_query_log_file = 'OAK-slow.log';
    SET global log_queries_not_using_indexes = ON;  #表示会记录没有使用索引的查询SQL
    SET long_query_time = 10;  #单位秒
    
    1. 查看慢日志

    1)用文本编辑器打开

    • time:日志记录的时间
    • User@Host:执行的用户及主机
    • Query_time:执行的时间
    • Lock_time:锁表时间
    • Rows_sent:发送给请求方的记录数,结果数量
    • Rows_examined:语句扫描的记录条数
    • SET timestamp:语句执行的时间点
    • select....:执行的具体的SQL语句

    2)使用mysqldumpslow查看

    MySQL 提供了一个慢查询日志分析工具mysqldumpslow,可以通过该工具分析慢查询日志内容。(需要安装perl环境)

    在MySQL的bin目录下执行命令:(注意慢日志文件目录不要带空格)

    perl mysqldumpslow.pl -t 5 -s AT D:\DESKTOP-C1N48D3-slow.log
    

    除了使用mysqldumpslow工具,也可以使用第三方分析工具,比如pt-query-digest、mysqlsla等。

    3. 慢查询优化

    • 增加索引
    • 索引覆盖
    • 提高索引过滤性

    如下sql:

    select * from student where age=18 and name like '张%';(全表扫
    描)
    

    优化1:我们可以增加索引

    alter table student add index(age,name);
    

    优化2:我们可以将name的第一个字取出来做一个虚拟列(first_name),然后创建一个联合索引(first_name,age)

    alter table student add first_name varchar(2) generated always as
     (left(name, 1)), add index(first_name, age);
    
  • 相关阅读:
    【Linux】【Services】【SaaS】Docker+kubernetes(2. 配置NTP服务chrony)
    【Linux】【Services】【DNS】使用Bind搭建DNS服务
    【Linux】【Services】【SaaS】Docker+kubernetes(1. 基础概念与架构图)
    【Services】【Web】【LVS】lvs基础概念
    jquery.cookie.js 配置
    SQL Server2008 TIME类型
    Ext.MessageBox
    Ext.Form 自动填写表单内容
    Ext 中xtype一览
    ExtGrid
  • 原文地址:https://www.cnblogs.com/javammc/p/16196445.html
Copyright © 2020-2023  润新知