Mysql索引总结

总结一下Mysql Innodb索引相关的知识,索引是以空间换时间的方式来加快查询速度。本质是将查询涉及的字段单独拎出来减少查询的基数和减少磁盘io次数,先做了排序可以用更高效的查询算法。

同时索引也有一些弊端,需要占用额外的空间,还不少。数据写入时,维护索引的数据排序,要消耗cpu。随着索引数量增加,查询优化器要评估每个索引的效率,对于用不到的索引的评估时间,影响查询效率。

索引分类

主键索引

primary key标注的列会被设置表的主键,可以是多个字段作为联合主键。Innodb的会按照主键顺序将记录组织成b-tree(实际是b+tree,统称为b-tree)形式。叶子结点存放记录数据,非叶子节点存放主键指作为索引的key。这棵b-tree就是主键索引。

普通索引

普通索引的结构也是b-tree,只是叶子结点存放的值不是记录,而是主键的值。所以,普通索引的使用流程是,现在索引上进行过滤,找到主键后,去主键索引里找到记录,这个过程称为回表查询。

唯一索引

唯一索引是在普通索引的基础上,加了唯一的约束,会在记录插入时,判断记录中包含的字段是否存在,存在则不允许插入。在查询的用法上跟唯一索引一样。

索引结构类型

B-tree索引

Innodb是用b+tree形式组织索引数据,b+tree是一颗多叉树,非叶子结点存放索引字段的值,叶子结点存放主键/记录。叶子结点有一个指针指向下一个叶子结点,提供范围查询的效率。

Hash索引

哈希索引将索引列以哈希表的形式存放,适合单值查询,不适合范围查询,所以使用的不多。Innodb有一个自适应哈希索引,会对索引上频繁访问的值,会在原有b-tree的索引之上,在内存中自动建立哈希索引,提高查询效率。

怎么使用索引

索引使用的三个原则

  1. 单行访问是慢的,一次磁盘io会获取一页数据,如果查询只用到数据页里的一行数据,性价比就很低。
  2. 按顺序查询数据是很快的,因为有机会用到顺序io,速度很快;另外顺序查询免去了排序的消耗。
  3. 索引覆盖查询很快,因为不需要回表,避免了单行访问。

所以最理想的情况是,用索引查询连续的结果集。

索引的三星原则

  1. 将查询相关数据放到一起
  2. 索引数据顺序和查询顺序一致,使order by能用到索引
  3. 索引的接包含查询中需要的全部列

实例要看查询优化器的结果,用explain判断索引是否生效。

索引使用方式

前缀索引

当索引的列值很大,例如对url加了索引,一个磁盘页(16kb)能存的索引记录数就越少,查询索引就需要读取更多的磁盘页,降低查询效率。

Innodb支持前缀索引,只对列的前一部分内容做索引,能显著减少索引值大小。

alter table post add index idx_url(url(100));

使用前缀索引时,要保证放入索引的部分内容的选择性。选择性越高,使用索引一次判断能过滤掉的记录数就越多,查询的效果就越好。选择性的计算公式一般是:

select count(distinct substr(url, 1, 10)) / count(1) from post;
-- 0.5806

多列索引

当一次查询用到多个字段时,我们可以对查询列组合起来建立一个索引,这样的索引叫多列索引或联合索引。

alter table post add index idx_title_author(title, author);

多列索引在能解决单列索引的很多问题,当然它也有一些自身的问题。我们先看下单列索引有什么问题。

工作中碰到一个同事,他把表的每个字段都加上索引,说这样在任何查询至少能用到1个索引。这样的方式很简单,但往往不是最优的方式。

以select id from post where category = ’game’ and hot = 100,在category和hot上都有索引。如果索引只命中了category一个索引,就需要回表查询hot=100,回表的操作是随机io,可能比顺序的全表扫描还慢。当然,mysql会使用一种索引合并的技术,使用表中多个单列索引来定位记录。这种情况下,category和hot都能击中索引。

**索引合并**
索引合并支持or、and和混合的情况。使用explain能看到type=index_merge,并且能在extra里看到using union(idx_category, idx_hot)等信息。
索引合并事实上不是一个好的选择。对于and的情况出现合并索引,最好是改成多列索引。对于or的情况,在对数据进行排序和合并时,合并算法会消耗大量cpu和内存。并且查询优化器还看不到这部分的消耗,导致实际查询成本比优化器提示的成本要高很多。
所以,尽量别用索引合并的功能,可以通过optimizer_switch来关闭该功能。

索引列的顺序

多列索引对索引列要满足最左匹配原则,即左边的列先满足查询条件,才会用上下一个列。并且,前面列的选择性越好,过滤掉越多的记录,那下一个列需要过滤的基数就越少。所以,我们一般会将选择性最高的列放在最左边。

但也会有特殊的情况,例如select id from post where author_id = 1 and category = ’game’; author_id值区间是1-6,1是管理员账号,category值有5种。现在author_id 2-6的人在不同category下发了一片文章,author_id为1的管理员也在不同category下发了一片文章。这时候author_id的选择性是6/10=0.6,category的选择性是5/10=0.5,按照经验是把author_id放在多列索引的前面。而上面这条查询,先查author_id后会返回5条记录,而现查category后会返回2条记录,所以category先查会更优一点。

上面这个情况是个特例,用来说明对索引顺序的选择要结合实际情况,但系统往往是被这种特殊的情况而击垮。

另外,是否要把单列索引尽可能换成多列索引呢?

当然不是,使用多列索引是有成本的,多列索引在多值查询的时候有收益,但是对于单值查询来说,就有损耗了。因为多列索引的key会变长,并且b-tree节点数变多,会让索引的体积变大。那么单列查询的性能就降低了。

隐藏的多列索引

由于非聚簇索引的叶子节点是主键id,并且id值是有序的,所以非聚簇索引默认和id组合成了多列索引。例如单列索引idx_author(author),它实际的效果跟idx_author(author, id)是一样的,多列所有也是一样的道理。

覆盖索引

索引的列包含查询所需的所有信息时,包括select、where、order by、group by子句涉及的列,这时不需要二次回表,这样的索引称为覆盖索引。

覆盖索引拥有非常优秀的性能,在查询当击中时,explain的extra字段会包含using index值。

使用索引来排序

Mysql索引除了能用来过滤记录,还能用在order by帮助排序。当排序击中索引时,explain的type=index;未击中索引时,extra字段会保护using filesort。

使用索引进行排序有几个条件:

  1. 索引的顺序和order by子句的顺序完全一样,并且所有列的排序方向都一样
  2. 联合查询语句,order by引用的列要全部在第一张表中
  3. 要满足索引最左前缀的要求

当然,并不是满足条件就会使用索引排序,还要根据查询优化器的总和评估成本。例如,排序完还需要回表查询其他字段,当回表次数多时,就不会使用索引信息,直接通过全表扫描后再排序。

索引下推

在mysql5.6开始,在索引遍历的过程中,优先用索引的字段进行过滤,减少回表次数。例如查询语句a like ‘x%’ and b = ‘y’ and c = ‘z’的时候,联合索引(a,b)根据最左匹配原则只能用到索引a字段,然后就需要回表查询到b字段再进行比较。有了索引下推,就能优先使用索引里的b字段进行过滤,然后再去回表查询。

聚簇索引

主键值连续且自增的好处

  1. 按顺序添加数据页,新数据都在新的数据页,可以一次性写入磁盘,性能更好。
  2. 可以避免数据页的分裂,减少数据碎片,占用索引空间更小。

缺点

在高并发的场景会有写入竞争。对主键上界会成为热点。会导致间隙锁的竞争。如果用到了自增,会对自增锁有竞争。

自增锁可以通过修改自增算法来优化,修改innodb_autoinc_lock_mode的值:

0:传统模式,持有自增锁,执行完语句后释放锁。

1:连续模式,持有mutex锁,在明确插入记录数 情况下,拿到对应数量的值就释放锁。

2:交叉模式,持有mutex锁,可以并发过去值。对于binlog等于statement的同步方式,可能造成master和slaver的值不一样。

查询未使用的索引

通过sys.table_io_waits_summary_by_index_usag找到未使用的索引,及时将无效的索引删除

损坏的索引文件

当索引文件因为各种原因会出现损坏的情况,就会导致出现莫名其妙的问题了,返回错误的结果或出现主键冲突等。这时候可以通过check table命令检查表索引是否损坏,然后通过repair table命令修复表索引。有的引擎不支持该命令,也可以通过没有操作的alter命令来重建索引,例如alter table user engin=innodb;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/180375.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DelayQueue介绍

5.1 DelayQueue介绍&应用 DelayQueue就是一个延迟队列,生产者写入一个消息,这个消息还有直接被消费的延迟时间。 需要让消息具有延迟的特性。 DelayQueue也是基于二叉堆结构实现的,甚至本事就是基于PriorityQueue实现的功能。二叉堆结构…

内置函数【MySQL】

文章目录 MySQL 内置函数日期和时间函数字符串函数数学函数信息函数参考资料 MySQL 内置函数 MySQL 的内置函数主要分为以下几种: 字符串函数:用于对字符串进行操作,如连接、截取、替换、反转、格式化等。数值函数:用于对数值进…

Go语言使用AES加密解密

Go语言提供了标准库中的crypto/aes包来支持AES加密和解密。下面是使用AES-128-CBC模式加密和解密的示例代码: package mainimport ("crypto/aes""crypto/cipher""encoding/base64""fmt" )func main() {key : []byte("…

使用 Mybatis 的 TypeHandler 存取 Postgresql jsonb 类型

文章目录 使用 TypeHandler 存取 Postgresql jsonb 类型常见错误column "" is of type jsonb but expression is of type character varying 使用 TypeHandler 存取 Postgresql jsonb 类型 首先在数据库表中定义 jsonb 类型: create table tb_user_info…

Android Studio导入项目一直显示正在下载Gradle项目

如题,问题图类似如下: (此图是解决以后截的,之前遇到问题没截图) 解决方法 先找到你正在下载的gradle的版本是哪个 然后在链接中 ​​​​​​Gradle Distributions 找到你所对于gradle的版本,下载对应…

React 和 Vue 在技术层面有哪些区别?

React 和 Vue 是两个非常流行的前端框架,它们在技术层面有以下几点区别: 数据驱动方式不同:React 的数据驱动是单向的,即从父组件向子组件传递数据,子组件不能直接修改父组件的数据。Vue 的数据驱动则是双向的&#xf…

【攻防世界-misc】János-the-Ripper

1.下载并解压桌面 2.用记事本打开misc100,可以看见文件里面是有flag.txt文件的, 3.将文件复制到虚拟机kali中,使用命令:binwalk -e 桌面/misc100 4.解压完以后打开桌面,会出现一个分离后的文件夹,打开文件…

windows10 Arcgis pro3.0-3.1

我先安装的arcgis pro3.0,然后下载的3.1。 3.0里面有pro、help、sdk、还有一些补丁包根据个人情况安装。 3.1里面也是这些。 下载 正版试用最新的 ArcGIS Pro 21 天教程,仅需五步!-地理信息云 (giscloud.com.cn) 1、安装windowsdesktop-…

Git删除临时分支

愿所有美好如期而遇 软件开发过程中,总有功能要添加进来,当我们有一个功能开发了一半的时候,产品经理说这个功能不需要了,尽管很无奈,但还是要删除,我开发到一半的分支如何删除呢? 所以需要使用…

第14关 快速定位业务服务慢的问题:利用 Ingress-Nginx 和日志查询实现高效故障排查

大家好,我是博哥爱运维。 有这样的一个生产场景,客户访问我们的服务请求超时或感觉很慢的时候,会向我们的客服反馈问题,这个时候,客服就会来找到我们运维让帮助排查下原因。 这里我们运维人员首先要对自己业务的整个…

记录Windows下安装redis的过程

开源博客项目Blog支持使用EasyCaching组件操作redis等缓存数据库,在继续学习开源博客项目Blog之前,准备先学习redis和EasyCaching组件的基本用法,本文记录在Windows下安装redis的过程。   虽然redis官网文档写着支持Linux、macOS、Windows等…

冒泡排序以及改进方案

冒泡排序以及改进方案 介绍: 冒泡排序属于一种典型的交换排序(两两比较)。冒泡排序就像是把一杯子里的气泡一个个往上冒一样。它不断比较相邻的元素,如果顺序不对就像水泡一样交换它们的位置,直到整个序列像水泡一样…

使用opencv实现更换证件照背景颜色

1 概述 生活中经常要用到各种要求的证件照电子版,红底,蓝底,白底等,大部分情况我们只有其中一种,本文通过opencv实现证件照背景的颜色替换。 1.1 opencv介绍 OpenCV(Open Source Computer Vision Librar…

UI上传组件异步上传更改为同步

实现异步方法 JavaScript 异步 实现异步的五种实现方法_js异步-CSDN博客 这两种比较经常用。 因为上传组件是异步上传的通过Async和await配合使用可以上传完照片视频后返回的地址在继续走下去,而不是图片视频地址还未获取时就上传后端了。

java文件上传以及使用阿里云OSS

JavaWeb 文件上传本地存储阿里云OSS配置文件 yml配置文件 文件上传 前端页面三要素: 表单项type“file” 表单提交方式post 表单的enctype属性multipart/form-data 本地存储 保证上传的文件不重复 //获取原始文件名String originalFilename image.getOriginalFi…

计算机毕业设计 基于PHP的考研互助交流系统的设计与实现 Java实战项目 附源码+文档+视频讲解

博主介绍:✌从事软件开发10年之余,专注于Java技术领域、Python人工智能及数据挖掘、小程序项目开发和Android项目开发等。CSDN、掘金、华为云、InfoQ、阿里云等平台优质作者✌ 🍅文末获取源码联系🍅 👇🏻 精…

机器学习笔记 - 基于百度飞桨PaddleSeg的人体分割

一、简述 虽然Segment Anything用于图像分割的通用大模型看起来很酷(飞桨也提供分割一切的模型),但是个人感觉落地应用的时候心里还是更倾向于飞桨这种场景式的,因为需要用到一些人体分割的需求,所以这里主要是对飞桨高性能图像分割开发套件进行了解和使用,但是暂时不训练…

day64 django中间件的复习使用

django中间件 django中间件是django的门户 1.请求来的时候需要先经过中间件才能达到真正的django后端 2.响应走的时候也需要经过中间件 ​ djangp自带七个中间件MIDDLEWARE [django.middleware.security.SecurityMiddleware,django.contrib.sessions.middleware.SessionMiddle…

解决Maven项目jar包下载失败的问题

文章目录 配置国内的Maven源引入正确的settings.xml文件重新下载jar包对后面要创建的新项目也统一配置仍然失败的解决办法 配置国内的Maven源 引入正确的settings.xml文件 如果该目录下的 settings.xml文件不存在或者错误,要创建一个 settings.xml文件并写入正确的…

Java 常用容器

目录 列表栈&#xff08;类&#xff09;队列(接口)setMap 列表 package com.czl;import java.util.ArrayList; import java.util.List; //AltEnter导入包 public class Main {public static void main(String[] args) throws Exception{List<Integer> list new ArrayLis…