MySQL中的索引index(超详细)

2023-11-02

概念:

在MySQL中,索引(index)是一种特殊的数据结构,它能够加快数据库中数据的检索速度。索引可以看做是一本书的目录,它提供了一种快速查找数据的方式。

MySQL中的索引是建立在一张表的一列或多列上的,用于加快对表中数据的查找速度。索引可以是单列索引,也可以是多列索引。当我们在一个表上创建了索引后,MySQL就会根据这个索引来建立一个索引文件,该文件中存储着每个值对应的行的物理位置。

MySQL支持多种类型的索引,例如B-tree索引、哈希索引、全文索引等。其中,B-tree索引是最常见和常用的索引类型,它可以在查询时进行快速的范围查找、排序和分组操作。

在数据库中使用索引可以大大提高数据的检索速度,但同时也会增加索引维护的开销,例如索引的创建、更新和删除操作。因此,索引的设计和使用需要根据具体的业务场景进行权衡和选择。

什么是索引?

  索引就是MySQL中可以高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护着满足 特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据, 这样就可以在这些数据结构 上实现高级查找算法,这种数据结构就是索引。

    添加索引原则上来说可以大大的提高数据获取的效率。

索引的优势:

        提高数据检索的效率,降低数据库 的IO成本。

        通过索引列对数据进行排序,降低 数据排序的成本,降低CPU的消 耗。

索引的劣势:

        索引也是占用空间的。

        索引大大提高了查询效率,同时却也降低更新表的速度, 如对表进行INSERT、UPDATE、DELETE时,效率降低。

索引结构


 概述
        MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,索引都有B+Tree索引、Hash索引、R-tree(空间索 引) 、Full-text(全文 索引)。我们常用的为B+Tree和Hash索引。

 B+Tree
        B+Tree是B-Tree的变种,主要有以下三点区别:

  •          所有的数据都会出现在叶子节点。
  •          叶子节点形成一个单向链表。
  •          非叶子节点仅仅起到索引数据作用,具体的数据都是在叶子节点存放的。

        然而MySQL中又对B+Tree做了优化, 在原 B+Tree 的基础上,增加一个指向相邻叶子节点 的链表指针,就形成了带有顺序指针的 B+Tree ,提高区间访问的性能,利于排序。
Hash
        MySQL中除了支持B+Tree索引,还支持一种索引类型---Hash索引。

        哈希索引就是采用一定的hash算法,将键值换算成新的hash值,映射到对应的槽位上,然后存储在 hash表中。

        如果两个(或多个)键值,映射到一个相同的槽位上,他们就产生了hash冲突(也称为hash碰撞),可 以通过链表来解决,如果了解java的话应该很好理解。

Hash索引的优点:

        查询效率高,通常(不存在hash冲突的情况)只需要一次检索就可以了,效率通常要高于B+tree索引。

Hash索引的缺点:
        Hash 索引只能用于对等比较 (= , in) ,不支持范围查询( between , > , < , ... ) 。
        
         无法利用索引完成排序操作 。


 索引分类


索引分类
        在MySQL数据库,将索引的具体类型主要分为以下几类:主键索引、唯一索引、常规索引、全文索引。

聚集索引&二级索引
        而在在InnoDB存储引擎(MySQL默认存储引擎)中,根据索引的存储形式,又可以分为以下两种:

 聚集索引选取规则:
        如果存在主键,主键索引就是聚集索引。

        如果不存在主键,将使用第一个唯一(UNIQUE)索引作为聚集索引。

        如果表没有主键,且没有合适唯一索引,InnoDB会自动生成一个rowid作为隐藏的聚集索引。

聚集索引&二级索引的区别:

        聚集索引的叶子节点下挂的是这一行的数据 。
        二级索引的叶子节点下挂的是该字段值对应的主键值。


 索引语法


创建索引:

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

        演示:例如给user表的name字段添加索引,中括号里的参数是可以省略的。

        CREATE INDEX idx_user_name ON user(name);

 查看索引:

        SHOW INDEX FROM table_name ;

        演示:例如查看user表中的索引。

        SHOW INDEX FROM user ;


删除索引:

        DROP INDEX index_name ON table_name ;

        演示:例如删除我们刚刚创建的索引。

        DROP INDEX idx_user_name ON user ;

5 索引使用
        介绍索引的使用之前,我们先要了解一下explain这个函数

explain
        EXPLAIN 或者 DESC命令获取 MySQL 如何执行 SELECT 语句的信息,包括在 SELECT 语句执行 过程中表如何连接和连接的顺序。

语法:

        直接在select语句之前加上关键字 explain / desc即可。

        EXPLAIN SELECT 字段列表 FROM 表名 WHERE 条件 ;

        例如:我要查询user表中id=1的数据,其中id为主键索引

        explain select * from tb_user where id = 1;

简单介绍一下比较重要的参数:

type:表示连接类型,性能由好到差的连接类型为NULL、system、const、 eq_ref、ref、range、 index、all 。在我们编写代码时,type尽量要往前靠。

possible_key: 显示可能应用在这张表上的索引,一个或多个。
key: 实际使用的索引,如果为 NULL ,则没有使用索引。
key_len: 表示索引中使用的字节数, 该值为索引字段最大可能长度,并非实际使用长度,在不损失精确性的前提下, 长度越短越好 。


最左前缀法则


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

        以tb_user表为例,我们先看一下tb_user表创建的索引。

   在 tb_user 表中,有一个联合索引,这个联合索引涉及到三个字段,顺序分别为:profession, age,status。

在执行以下代码时:

  explain select * from tb_user where profession = '软件工程' and age = 31 and status = '0';

  可以看到在这里使用到了索引的,key_len为54。

   explain select * from tb_user where profession = '软件工程';

 可以看到满足最左前缀法则时是可以用到索引的,key_len=47;

explain select * from tb_user where profession = '软件工程' and status = '0';

可以看到status字段是不符合最左前缀法则的,跳过了联合索引中间的age字段,这时的key_len的 长度也为47。所以可以得出若不满足最最前缀法则实惠导致联合索引部分失效的情况。

范围查询


 联合索引中,出现范围查询(>,<),范围查询右侧的列索引失效。

 explain select * from tb_user where profession = '软件工程' and age > 30 and status = '0';

     当范围查询使用> 或 < 时,走联合索引了,联合索引全走长度为54这里索引的长度为49,就说明范围查询右边的status字段是没有走索引的。

索引失效情况


 字符串不加引号


   字符串类型字段使用时,不加引号,索引将失效

   explain select * from tb_user where profession = '软件工程' and age = 31 and status = 0;

如果字符串不加单引号,对于查询结果,没什么影响,但是数据库存在隐式类型转换,key_len长度为49,索引部分失效了。

 索引列运算


 若在索引列上进行运算操作, 索引则会失效。

explain select * from tb_user where substring(profession,1,2) = '软件' and age = 31 and status = 0;

 可以看到联合索引直接全部失效了,这里若是单例索引也会失效的。

 模糊查询

   如果仅仅是尾部模糊匹配,索引不会失效。如果是头部模糊匹配,索引失效。执行以下两句代码:

    explain select * from tb_user where profession like '软件%';

    explain select * from tb_user where profession like '%工程';

经过上述的测试,我们发现,在like模糊查询中,在关键字后面加%,索引可以生效。而如果在关键字 前面加了%,索引将会失效。

 or连接条件

用or分割开的条件, 如果or前的条件中的列有索引,而后面的列中没有索引,那么涉及的索引都不会被用到。

  先看下tb_user表的索引情况。

explain select * from tb_user where id = 10 or age = 23;

 

可以看到id是主键索引,而age并没有索引,所以这里索引失效了。

 SQL提示

  SQL提示,是优化数据库的一个重要手段,简单来说,就是在 SQL 语句中加入一些人为的提示来达到优 化操作的目的。
        use index : 建议MySQL使用哪一个索引完成此次查询(仅仅是建议,mysql内部还会再次进 行评估)。

        explain select * from tb_user use index(idx_user_pro) where profession = '软件工程';

 ignore index : 忽略指定的索引。

 explain select * from tb_user ignore index(idx_user_pro) where profession = '软件工程';

 

 force index : 强制使用索引。

 explain select * from tb_user force index(idx_user_pro) where profession = '软件工程';

 

 覆盖索引

尽量使用覆盖索引,减少select *。 那么什么是覆盖索引呢? 覆盖索引是指 查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到 。

        也就是你要获取的数据就在叶子节点存放的键值以及主键id内。

索引前缀

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

语法: create index idx_xxxx on table_name(column(n)) ;

示例: 为tb_user表的email字段,建立长度为5的前缀索引。

create index idx_email_5 on tb_user(email(5));

  单例索引和联合索引 

  1.         单列索引:即一个索引只包含单个列。
  2.         联合索引:即一个索引包含了多个列。

        在业务场景中,如果存在多个查询条件,考虑针对于查询字段建立索引时,建议建立联合索引, 而非单列索引。

索引设置原则

  1.  针对于数据量较大,且查询比较频繁的表建立索引。
  2.  针对于常作为查询条件(where)、排序(order by)、分组(group by)操作的字段建立引。
  3.  尽量选择区分度高的列作为索引,尽量建立唯一索引,区分度越高,使用索引的效率越高。
  4.  如果是字符串类型的字段,字段的长度较长,可以针对于字段的特点,建立前缀索引。
  5.  尽量使用联合索引,减少单列索引,查询时,联合索引很多时候可以覆盖索引,节省存储空间避免回表,提高查询效率。
  6. 要控制索引的数量,索引并不是多多益善,索引越多,维护索引结构的代价也就越大,会影响增删改的效率。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MySQL中的索引index(超详细) 的相关文章

  • Hibernate 可以使用 MySQL 的“ON DUPLICATE KEY UPDATE”语法吗?

    MySQL 支持 INSERT ON DUPLICATE KEY UPDATE 语法允许您 盲目 插入数据库 并回退到更新现有记录 如果存在 当您想要快速事务隔离并且想要更新的值取决于数据库中已有的值时 这非常有用 作为一个人为的示例 假设
  • MySQL有两个不同的密码?

    我确信它们是不同事物的密码 但我不确定是什么 当在终端连接到 MySQL 时 我输入 usr LOCAL mysql BIN mysql h host u username p然后系统会提示我输入密码 密码是 但是当使用 PHP 连接到 M
  • Java 从 SQL 数组获取 ResultSet 失败

    我试图从数据库中检索电子邮件地址 但没有成功 我的代码如下 Main System out println PortfolioData getEmails 58 So Far Returning null 投资组合数据 public sta
  • 使用mysql在一个查询中选择多个表中的子项总数

    我整个下午都在尝试处理一个查询 或两个或三个 以获得三个表的所有子表的计数 看看我的设计 用户表 id user name 1 foo 2 bar 赢表 id won user 1 1 2 1 3 2 绘制表格 id draw user 1
  • MySQL InnoDB 查询性能

    我正在尝试优化一个简单的 sql 查询 该查询将多次运行大量数据 这是场景 MySQL 与 InnoDB 表 where 和 join 中使用的所有字段都已索引 表有 FK 我不需要查询的整个缓存 但每个表的缓存是可能的 表有更多的更新 插
  • C#:SQL 查询生成器类

    在哪里可以找到好的 SQL 查询构建器类 我只需要一个简单的类来构建 SQL 字符串 仅此而已 我需要它用于 C 和 MySql 我真的不需要像 Linq 或 NHibernate 这样的东西 谢谢 由于 Google 将我引导至此页面 我
  • 将 UPDATE 转换为 INSERT INTO ON DUPLICATE KEY UPDATE 语句

    我有这个 UPDATE MySQL 语句 效果很好 UPDATE table1 Inner Join table2 ON table2 id table1 gw id SET table1 field1 1 table1 field2 2
  • MySQL+子串怎么做? + 替换?

    我不太擅长 SQL 希望能够变得更好 我在尝试执行某些表操作时遇到一些麻烦 我希望能够从下面的 ProgUID 列中选择子字符串 就像是 SUBSTRING table ProgUID 3 12 这将为我提供 ProgUID P CAMVE
  • MySQL 服务器未启动

    当我做 mysql u root p并输入my password这就是我得到的 错误 2002 HY000 无法通过套接字 var run mysqld mysqld sock 连接到本地 MySQL 服务器 2 所以我输入 systemc
  • PHP 选择后立即删除

    我有一个 PHP 服务器脚本 它从 MySQL 数据库中选择一些数据 一旦我将 mysql query 和 mysql fetch assoc 的结果存储在我自己的局部变量中 我就想删除我刚刚选择的行 这种方法的问题在于 PHP 似乎对我的
  • 当“修复表”查询在 mysql 中不起作用时该怎么办?

    我收到此错误 表的存储引擎不支持修复 当我尝试使用查询修复表时repair table tbl college master 表是 innodb 类型 但我不知道我收到此错误 See 手册 http dev mysql com doc re
  • Mysql innoDB 不断崩溃[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我的数据库 mysql 服务器不断崩溃 重新启动 我不知道该怎么办 我不断在 dbname org err 文件中收到以下内容 13120
  • Python:如何使用生成器来避免 sql 内存问题

    我有以下方法来访问 mysql 数据库 并且查询在服务器中执行 我无权更改有关增加内存的任何内容 我对生成器很陌生 并开始阅读更多有关它的内容 并认为我可以将其转换为使用生成器 def getUNames self globalUserQu
  • 如何使用 MySQL 的 LOAD DATA LOCAL INFILE 在导入 CSV 时将字符串日期更改为 MySQL 日期格式

    我正在使用 MySQL 的 LOAD DATA LOCAL INFILE SQL 语句将数据从 CSV 文件加载到现有数据库表中 下面是一个 SQL 语句示例 LOAD DATA LOCAL INFILE file csv INTO TAB
  • 如何在 Laravel 查询中使用多个 OR,AND 条件

    我需要 Laravel 查询帮助 我的自定义查询 返回正确结果 Select FROM events WHERE status 0 AND type public or type private 如何写这个查询Laravel Event w
  • PHP 绑定“bigint”数据类型(MySQLi 准备好的语句)

    studentId 57004542323382 companyOfferId 7 sql INSERT INTO studentPlacement companyOfferId studentId VALUES if stmt db gt
  • 截断 Mysql 表 Cron 作业?

    我在如何使用 cron 作业截断 Mysql 表时遇到了一些麻烦 无论我尝试什么 我似乎都无法让数据库清除表格 感谢您的帮助 mysql uderp example pexample hlocalhost Dexample e TRUNCA
  • Mysql 检索所有有限制的行

    我想检索特定用户的所有行 限制为 0 x 所以我只是想问是否有任何方法可以检索 mysql 中的所有行 而不调用返回 x 的 count id 的方法 而不重载现有函数 该函数在查询中根本没有限制 与我们的 string Relace 功能
  • Mysql 中 UNION 子句的替代方案

    我有两张桌子 表 a 表 b table a ID 1 2 3 4 5 7 table b ID 2 3 4 5 6 我必须得到这样的输出而无需UNION命令 ID 1 2 3 4 5 6 7 注意 我有一个联合解决方案 select fr
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri

随机推荐

  • Altium Designer -- EMC/EMI电路设计经验

    一 基本概念 参看 电磁兼容原理及应用 讲的相当的不错 随着科学技术的不断发展 各种电气和电子设备已广泛应用于国民经济的各个部门以及人们的日常生活中 电气和电子设备在正常运行的同时 也往外发射有用或无用的电磁能量 这些能量会影响其它设备的正
  • 【React】dva-cli建立脚手架后引用css 无效

    用dva cli作为脚手架建立工程后 开始尝试编写页面 然后立马发现一个坑爹的问题 在我less文件里面写了一个class 比如 MainHead 但是编译出来之后发现css文件里面变成了 MainHead xuaz 多了一个后缀 坑爹嘛这
  • JavaScript 预解析(面试经常问)

    文章目录 预解析 预解析 解析器运行 JS 分为哪两步 预解析 执行代码 预解析 js 引擎会把 js里面所有 var 还有 function 提前到当前作用域的最前面 执行代码 从上到下执行 预解析分为 变量预解析 变量提升 和函数预解析
  • 数字图像处理第一二章

    什么是数字图像处理 数字图像处理是指借助于数 计算机来处理数字图像 当x y和灰度值f是有限的离散数值时 称该图像为数字图像 一幅图像可定义为一个二维函数f x y 其中x和y是空间 平面 坐标 而在任一对空间坐标 x y 处的幅值f称为图
  • infix 关键字

    infix适用于有单个参数的扩展函数 如果一个函数使用了infix 关键字 接收者和函数之间的点操作 以及参数的一对括号可以省略 fun String printWithDefault0 default String print this
  • 动态路由协议BGP配置实战

    1 边界网关协议BGP BGP是自治系统路由协议 用于AS间交换路由信息 通常使用在运营商 运营商之间或是企业 运营商之间 目前广为使用的是BGP 4 支持CIDR BGP协议使用TCP179端口传输 同一AS的路由之间传输的协议称为IBG
  • 在HAL库中NVIC中断配置

    中断优先级分组配置 void HAL NVIC SetPriorityGrouping uint32 t PriorityGroup 配置函数 define IS NVIC PRIORITY GROUP GROUP GROUP NVIC P
  • 关于监控方案的一点想法供参考

    Author Skate Time 2017 12 11 关于监控方案的一点想法供参考 1 监控目标 监控的直接目标 及时 准确的发现潜在事件 并辅助运维人员处理生产事件 消除生产事件专家和高手与一线员工的区别 监控的增值目标 通过高度的可
  • SW3516中文资料书

    SW3516 是一款高集成度的快充车充芯片 支持 A C 口任意口快充输出 支持双口独立限流 其集成了 5A 高效率同步降压变换器 支持 PPS PD QC AFC FCP SCP PE SFCP 低压直充等多种快充协议 CC CV 模式
  • unity 使用声网(Agora)实现语音通话

    第一步 先申请一个声网账号 Agora官网链接 https console shengwang cn 第二步在官网创建项目 选择无证书模式 证书模式需要tokenh和Appld才能通话 第三步 官网下载SDK 然后导入到unity 也可以直
  • VulnHubBreach1.0[渗透测试]新手必看

    靶机下载地址 https download vulnhub com breach Breach 1 0 zip 前言 将下载好的靶场导入VMware 虚拟机设置网络模式为nat模式 即可开启渗透 阅读readme txt 作为多部分系列的第
  • linux 共享存储 iostat,Linux环境下存储监控工具nfsiostat介绍

    我对Linux下存储管理和监控工具的缺乏感到非常不满 虽然如此 我还是积极在寻找适合的工具 除了等待更好的工具出现 或自己开发一款 外 我们必须好好利用现有工具的功能 sysstat监控工具家族中的一员 在以前的文章中 我曾经介绍过iost
  • mmdetection常见问题总结

    mmdetection运行以及问题总结 最近因为工作需要 跑了下mmdetection 复现了论文的精度 总结下其中遇到的问题 希望对大家有帮助哦 1 环境设置 操作系统 ubuntu16 04 python3 7 pytorch1 6 0
  • HYSBZ bzoj 1941 Hide and Seek

    Problem www lydsy com JudgeOnline problem php id 1941 vjudge net contest 187908 problem B Reference BZOJ1941 Sdoi2010 Hi
  • 翻译:Tree Energy Loss: Towards Sparsely Annotated Semantic Segmentation

    目录 摘要 介绍 方法描述 1 树亲和生成 2 级联过滤生成伪标签 3 为未标记的像素分配伪标签 文章地址 Tree Energy Loss Towards Sparsely Annotated Semantic Segmentation
  • 【Blender小技巧】点对齐

    使用吸附功能实现 设置完之后 选择要移动的对象 按G移动该对象 然后移动光标到要对齐的顶点即可 需要先将对象移动到要对齐的顶点旁 然后再重新按G移动对象才能较为精确 G Z顶点对齐中间点
  • 微搭低代码学习之基础操作

    低代码开发平台 是一种方便产生应用程序的平台软件 软件会开发环境让用户以图形化接口以及配置编写程序 而不是用传统的程序设计作法 此平台可能是针对 某些种类的应用而设计开发的 例如数据库 业务过程 以及用户界面 这类平台可能可以产生完整且可运
  • 常见数据结构

    先激励激励自己 数据结构是指组织数据的方式 它是算法的基础 线性结构和非线性结构 线性结构 是一个有序数据元素的集合 它应该满足下面的特征 集合中必存在唯一的一个 第一个元素 集合中必存在唯一的一个 最后的元素 除最后一元素之外 其它数据元
  • 《算法系列》之刷题准备

    简介 这里是刷题会用到的一些准备工作 和一些注意事项 习惯的养成 我们在leetcode上写题时 代码输入框都会有模板 甚至还有需要用到的数据结构 优点是可以沉浸式的只关心代码逻辑的书写 缺点是 你面试的时候 只有一张白纸 让你用笔写代码时
  • MySQL中的索引index(超详细)

    概念 在MySQL中 索引 index 是一种特殊的数据结构 它能够加快数据库中数据的检索速度 索引可以看做是一本书的目录 它提供了一种快速查找数据的方式 MySQL中的索引是建立在一张表的一列或多列上的 用于加快对表中数据的查找速度 索引