首页 > 数据库 >3.MySQL索引

3.MySQL索引

时间:2023-09-18 21:57:41浏览次数:42  
标签:查询 索引 MySQL 主键 数据 节点

1.索引:是一种用于快速查询和检索数据的数据结构,其本质可以看成是一种排序好的数据结构。
常见的索引结构有: B 树, B+树 和 Hash、红黑树。在 MySQL 中,无论是 Innodb 还是 MyIsam,都使用了 B+树作为索引结构。


2.索引优缺点:
优点: 使用索引可以大大加快数据的检索速度(大大减少检索的数据量), 这也是创建索引的最主要的原因。
    通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
缺点: 创建索引和维护索引需要耗费许多时间。当对表中数据进行增删改时,如果数据有索引,那么索引也需要动态修改,会降低SQL执行效率。
    索引需要使用物理文件存储,也会耗费一定空间
 
使用索引一定能提高查询性能吗?
  大多数情况下,索引查询都是比全表扫描要快的。但是如果数据库的数据量不大,那么使用索引也不一定能够带来很大提升。
 
3.索引的底层数据结构:
  (1)Hash表:哈希表是键值对的集合,通过键(key)即可快速取出对应的值(value),因此哈希表可以快速检索数据(接近 O(1))。
为何能够通过 key 快速取出 value 呢? 原因在于 哈希算法(也叫散列算法)。通过哈希算法,我们可以快速找到 key 对应的 index,找到了 index 也就找到了对应的 value。

hash = hashfunc(key);index = hash % array_size;

  哈希算法有个 Hash 冲突 问题,也就是说多个不同的 key 最后得到的 index 相同。通常情况下,常用的解决办法是 链地址法,链地址法就是将哈希冲突数据存放在链表中。就比如 JDK1.8 之前 HashMap 就是通过链地址法来解决哈希冲突的。不过,JDK1.8 以后HashMap为了减少链表过长的时候搜索时间过长引入了红黑树。
  为了减少 Hash 冲突的发生,一个好的哈希函数应该“均匀地”将数据分布在整个可能的哈希值集合中。
  为什么 MySQL 没有使用哈希表作为索引的数据结构呢? 主要是因为 Hash 索引不支持顺序和范围查询。假如我们要对表中的数据进行排序或者进行范围查询,那 Hash 索引可就不行了。并且,每次IO只能取一个。
  (2)B 树& B+树:B 树也称 B-树,全称为 多路平衡查找树,B+ 树是 B 树的一种变体。B 树和 B+树中的 B 是 Balanced (平衡)的意思。
   B 树& B+树两者有何异同呢?
   ·B 树的所有节点既存放键(key) 也存放 数据(data),而 B+树只有叶子节点存放 key 和 data,其他内节点只存放 key。
   ·B 树的叶子节点都是独立的;B+树的叶子节点有一条引用链指向与它相邻的叶子节点。
   ·B 树的检索的过程相当于对范围内的每个节点的关键字做二分查找,可能还没有到达叶子节点,检索就结束了。而 B+树的检索效率就很稳定了,任何查找都是从根节点到叶子节点的过程,叶子节点的顺序检索很明显。

  在 MySQL 中,MyISAM 引擎和 InnoDB 引擎都是使用 B+Tree 作为索引结构,但是,两者的实现方式不太一样。             
  MyISAM 引擎中,索引文件和数据文件是分离的,B+Tree 叶节点的 data 域存放的是数据记录的地址。在索引检索的时候,首先按照 B+Tree 搜索算法搜索索引,如果指定的 Key 存在,则取出其 data 域的值,然后以 data 域的值为地址读取相应的数据记录。这被称为“非聚簇索引(非聚集索引)”。
  InnoDB 引擎中,其数据文件本身就是索引文件。其表数据文件本身就是按 B+Tree 组织的一个索引结构,树的叶节点 data 域保存了完整的数据记录。这个索引的 key 是数据表的主键,因此 InnoDB 表数据文件本身就是主索引。这被称为“聚簇索引(聚集索引)”,而其余的索引都作为 辅助索引 ,辅助索引的 data 域存储相应记录主键的值而不是地址,这也是和 MyISAM 不同的地方。在根据主索引搜索时,直接找到 key 所在的节点即可取出数据;在根据辅助索引查找时,则需要先取出主键的值,再走一遍主索引。 因此,在设计表的时候,不建议使用过长的字段作为主键,也不建议使用非单调的字段作为主键,这样会造成主索引频繁分裂。

  (3)红黑树是一种自平衡二叉查找树,通过在插入和删除节点时进行颜色变换和旋转操作,使得树始终保持平衡状态,它具有以下特点:

  1. 每个节点非红即黑;
  2. 根节点总是黑色的;
  3. 每个叶子节点都是黑色的空节点(NIL 节点);
  4. 如果节点是红色的,则它的子节点必须是黑色的(反之不一定);
  5. 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度)。

 


4.索引分类:                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            (1)按照数据结构维度划分:
  B+Tree索引:MySQL 里默认和最常用的索引类型。只有叶子节点存储 value,非叶子节点只有指针和 key。存储引擎 MyISAM 和 InnoDB 实现 BTree 索引都是使用 B+Tree,但二者实现方式不一样(前面已经介绍了)。
  哈希索引:类似键值对的形式,一次即可定位。
  R树索引:一般不会使用,仅支持 geometry 数据类型,优势在于范围查找,效率较低,通常使用搜索引擎如 ElasticSearch 代替。
  全文索引:全文索引:对文本的内容进行分词,进行搜索。目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。一般不会使用,效率较低,通常使用搜索引擎如 ElasticSearch 代替。
(2)按照底层存储方式划分:
  聚簇索引(聚集索引)索引结构和数据一起存放,InnoDB 中的主键索引就属于聚簇索引。
  聚簇索引的优缺点
  优点 :
    查询速度非常快 :聚簇索引的查询速度非常的快,因为整个 B+树本身就是一颗多叉平衡树,叶子节点也都是有序的,定位到索引的节点,就相当于定位到了数据。相比于非聚簇索引, 聚簇索引少了一次读取数据的 IO 操作。
对排序查找和范围查找优化 :聚簇索引对于主键的排序查找和范围查找速度非常快。
  缺点 :
    依赖于有序的数据 :因为 B+树是多路平衡树,如果索引的数据不是有序的,那么就需要在插入时排序,如果数据是整型还好,否则类似于字符串或 UUID 这种又长又难比较的数据,插入或查找的速度肯定比较慢。
    更新代价大 : 如果对索引列的数据被修改时,那么对应的索引也将会被修改,而且聚簇索引的叶子节点还存放着数据,修改代价肯定是较大的,所以对于主键索引来说,主键一般都是不可被修改的。
 
非聚簇索引(非聚集索引)索引结构和数据分开存放的索引,二级索引(辅助索引)属于非聚簇索引。MySQL的MyISAM引擎,不管主键还是非主键,使用的都是非聚簇索引。
非聚集索引的优点
更新代价比聚集索引要小 。非聚集索引的更新代价就没有聚集索引那么大了,非聚集索引的叶子节点是不存放数据的
非聚集索引的缺点
跟聚集索引一样,非聚集索引也依赖于有序的数据
可能会二次查询(回表) :这应该是非聚集索引最大的缺点了。 当查到索引对应的指针或主键后,可能还需要根据指针或主键再到数据文件或表中查询。
 
按照应用维度划分:
·  主键索引:加速查询 + 列值唯一(不可以有 NULL)+ 表中只有一个。
·  普通索引:仅加速查询。
·  唯一索引:加速查询 + 列值唯一(可以有 NULL)。
·  覆盖索引:一个索引包含(或者说覆盖)所有需要查询的字段的值。
·  联合索引(组合索引、复合索引):多列值组成一个索引,专门用于组合搜索,其效率大于索引合并。
·  全文索引:对文本的内容进行分词,进行搜索。目前只有 CHAR、VARCHAR ,TEXT 列上可以创建全文索引。一般不会使用,效率较低,通常使用搜索引擎如 ElasticSearch 代替。
 
MySQL 8.x 中实现的索引新特性:
·  隐藏索引:也称为不可见索引,不会被优化器使用,但是仍然需要维护,通常会软删除和灰度发布的场景中使用。主键不能设置为隐藏(包括显式设置或隐式设置)。
·  降序索引:之前的版本就支持通过 desc 来指定索引为降序,但实际上创建的仍然是常规的升序索引。直到 MySQL 8.x 版本才开始真正支持降序索引。另外,在 MySQL 8.x 版本中,不再对 GROUP BY 语句进行隐式排序。
·  函数索引:从 MySQL 8.0.13 版本开始支持在索引中使用函数或者表达式的值,也就是在索引中可以包含函数或者表达式。
 
主键索引:primary key数据表的主键列使用的就是主键索引。一张数据表有只能有一个主键,并且主键不能为 null,不能重复。
在 MySQL 的 InnoDB 的表中,当没有显示的指定表的主键时,InnoDB 会自动先检查表中是否有唯一索引且不允许存在 null 值的字段,如果有,则选择该字段为默认的主键,否则 InnoDB 将会自动创建一个 6Byte 的自增主键。
 
二级索引:辅助索引,因为二级索引的叶子节点存储的数据是主键。也就是说,通过二级索引,可以定位主键的位置。
唯一索引,普通索引,前缀索引等索引属于二级索引。
·  唯一索引(Unique Key) :唯一索引也是一种约束。唯一索引的属性列不能出现重复的数据,但是允许数据为 NULL,一张表允许创建多个唯一索引。 建立唯一索引的目的大部分时候都是为了该属性列的数据的唯一性,而不是为了查询效率。
·  普通索引(Index) :普通索引的唯一作用就是为了快速查询数据,一张表允许创建多个普通索引,并允许数据重复和 NULL。
·  前缀索引(Prefix) :前缀索引只适用于字符串类型的数据。前缀索引是对文本的前几个字符创建索引,相比普通索引建立的数据更小, 因为只取前几个字符。
·  全文索引(Full Text) :全文索引主要是为了检索大文本数据中的关键字的信息,是目前搜索引擎数据库使用的一种技术。Mysql5.6 之前只有 MYISAM 引擎支持全文索引,5.6 之后 InnoDB 也支持了全文索引。
(6)非聚簇索引一定回表查询吗(覆盖索引)?非聚簇索引不一定回表查询。
·  覆盖索引:一个索引包含(或者说覆盖)所有需要查询的字段的值。
覆盖索引即需要查询的字段正好是索引的字段,那么直接根据该索引,就可以查到数据了,而无需回表查询。
如主键索引,如果一条 SQL 需要查询主键,那么正好根据主键索引就可以查到主键。
再如普通索引,如果一条 SQL 需要查询 name,name 字段正好有索引, 那么直接根据这个索引就可以查到数据,也无需回表。
 
(7)最左前缀匹配原则:
最左前缀匹配原则指的是,在使用联合索引时,MySQL 会根据联合索引中的字段顺序,从左到右依次到查询条件中去匹配,如果查询条件中存在与联合索引中最左侧字段相匹配的字段,则就会使用该字段过滤一批数据,直至联合索引中全部字段匹配完成,或者在执行过程中遇到范围查询(如 >、<)才会停止匹配。对于 >=、<=、BETWEEN、like 前缀匹配的范围查询,并不会停止匹配。所以,我们在使用联合索引时,可以将区分度高的字段放在最左边,这也可以过滤更多数据
 
(8)索引下推:是 MySQL 5.6 版本中提供的一项索引优化功能,可以在非聚簇索引遍历过程中,对索引中包含的字段先做判断,过滤掉不符合条件的记录,减少回表次数
 
(9)正确使用索引的一些建议:
不为 NULL 的字段 :索引字段的数据应该尽量不为 NULL,因为对于数据为 NULL 的字段,数据库较难优化。如果字段频繁被查询,但又避免不了为 NULL,建议使用 0,1,true,false 这样语义较为清晰的短值或短字符作为替代。
被频繁查询的字段 :我们创建索引的字段应该是查询操作非常频繁的字段。
作为条件查询的字段 :被作为 WHERE 条件查询的字段,应该被考虑建立索引。
频繁需要排序字段 :索引已经排序,这样查询可以利用索引的排序,加快排序查询。
·被经常频繁用于连接的字段 :经常用于连接的字段可能是一些外键列,对于外键列并不一定要建立外键,只是说该列涉及到表与表的关系。对于频繁被连接查询的字段,可以考虑建立索引,提高多表连接查询的效率。
 
被频繁更新的字段应该慎重建立索引虽然索引能带来查询上的效率,但是维护索引的成本也是不小的。 如果一个字段不被经常查询,反而被经常修改,那么就更不应该在这种字段上建立索引了。
 
限制每张表上的索引数量:
索引并不是越多越好,建议单张表索引不超过 5 个!
(1)索引可以增加查询效率,但同样也会降低插入和更新的效率,甚至有些情况下会降低查询效率。(2)并且 MySQL 优化器在选择如何优化查询时,会根据统一信息,对每一个可以用到的索引来进行评估,以生成出一个最好的执行计划,如果同时有很多个索引都可以用于查询,就会增加 MySQL 优化器生成执行计划的时间,同样会降低查询性能。
 
尽可能的考虑建立联合索引而不是单列索引

标签:查询,索引,MySQL,主键,数据,节点
From: https://www.cnblogs.com/cjhtxdy/p/17713165.html

相关文章

  • MYSQL SQL做题总结
    一.关于join1.内外左右连接2.交叉联结(corssjoin)使用交叉联结会将两个表中所有的数据两两组合。如下图,是对表“text”自身进行交叉联结的结果:3.三表双双连接力扣题目a与b表笛卡尔积,再与c表左连接。SELECTa.student_id,a.student_name,b.subject_name,count(c.subject......
  • MySQL主从复制原理
    一张图让你牢记MySQL主从复制原理|原创(qq.com)为什么需要主从复制?1、读写分离,增强MySQL数据库的可用性。2、做数据的热备。3、架构的扩展。业务量越来越大,I/O访问频率过高,单机无法满足,此时做多库的存储,降低磁盘I/O访问的频率,提高单个机器的I/O性能。说说BinlogMySQL的Server......
  • MySQL三大日志(binlog、redo log和undo log)详解
    硬核干货!一文掌握binlog、redolog、undolog(qq.com)MySQL日志:undolog、redolog、binlog(qq.com)MySQL三大日志(binlog、redolog和undolog)详解|JavaGuide(Java面试+学习指南)MySQL日志主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其......
  • 一般是单个索引使用多还是组合索引使用多
    在大多数情况下,单个索引通常比组合索引更常用。这是因为单个索引可以满足许多查询的需求,并且在某些情况下,它们可能比组合索引更有效。以下是一些适合使用单个索引的情况:单列查询条件:当查询语句只涉及一个列的条件时,使用单个索引可以满足查询的需求。这种情况下,使用单个索引可以更好......
  • 1.MySQL、基础架构(SQL语句执行流程、更新语句执行流程)
    1.MySQL的索引有哪些索引在什么层面:索引是在存储引擎层实现的,而不是在服务器层实现的,所以不同存储引擎具有不同的索引类型和实现。B+树索引:是大多数MySQL存储引擎的默认索引类型。哈希索引:哈希索引能以O(1)时间进行查找,但是失去了有序性;InnoDB存储引擎有一个特殊的功能叫......
  • MySQL事务隔离级别详解
    MySQL事务隔离级别详解|JavaGuide(Java面试+学习指南)事务隔离级别总结SQL标准定义了四个隔离级别:READ-UNCOMMITTED(读取未提交):最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。READ-COMMITTED(读取已提交):允许读取并发事务已经提交的数......
  • Linux离线安装Mysql-5.7
    1、背景描述在真实业务场景下,Linux服务器一般位于内网,所以无法直接访问互联网资源;特别是安装数据库的Linux服务器,在网络方面的管控只会更加严格;因此,需要提前下载好相关资源,再传输到内网Linux服务器进行安装;2、下载Mysql的安装包下载地址:https://dev.mysql.com/downl......
  • 无法访问MySQL,错误代码1045 (28000): 用户'bill'@'localhost'被拒绝访问
    这个错误通常是由于权限设置不正确或者密码错误导致的。你可以尝试以下解决方案来解决这个问题:确保密码输入正确:在输入密码时要注意区分大小写,确保将正确的密码输入。检查用户权限:使用root用户登录MySQL,执行以下命令来查看用户bill的权限:SHOWGRANTSFOR'bill'@'localhost';确认用......
  • openGauss学习笔记-73 openGauss 数据库管理-创建和管理索引
    openGauss学习笔记-73openGauss数据库管理-创建和管理索引73.1背景信息索引可以提高数据的访问速度,但同时也增加了插入、更新和删除操作的处理时间。所以是否要为表增加索引,索引建立在哪些字段上,是创建索引前必须要考虑的问题。需要分析应用程序的业务处理、数据使用、经常被......
  • 世界第5大搜索引擎Yandex爆出源码后获得的其内部若干排名因素
    相关新闻:中文翻译版:https://mbd.baidu.com/newspage/data/landingsuper?context=%7B%22nid%22%3A%22news_9394501005789721090%22%7D&n_type=-1&p_from=-1英文版:https://www.hackread.com/yandex-source-code-hacked-leaked/  =============================      ========......