聊聊MySql索引的类型以及失效场景
文章目录
- 概念
- 常见的索引
- 1.B树索引
- 2.哈希索引
- 3.全文索引
- 4.空间索引
- 5.聚集索引
- 如何设计合理?
- 1.明确索引需求
- 2.选择索引列
- 3.选择索引类型
- 4.考虑索引维护开销
- 5.设计联合索引
- 6.删除不必要索引
- 7.关注索引统计信息
- 8.测试查询效果
- 常见不生效场景
- 1.全表扫描
- 2.索引列计算
- 3.模糊查询未用前置匹配
- 4.复合索引条件次序错误
- 5.or条件索引无效
- 6.子查询或关联查询inner side未用索引
- 7.数据分布严重不均匀
- 8.返回未命中索引覆盖字段
- 9.索引统计信息没有及时更新
- 总结
- 写在最后

概念
索引是数据库管理系统中一个重要的优化结构,目的是提高数据库查询和操作的速度。
索引的工作原理是对数据库表中的一列或多列的值进行预排序,然后存储该列值与数据行的地址映射,在查询时可以直接查找到数据,而无需全表扫描。
常见的索引
1.B树索引
最常见的索引类型,可以对一个或多个列创建索引。
2.哈希索引
通过哈希函数直接定位到数据行。查找速度极快,但只支持等值查询。
3.全文索引
可以对文本中的关键词创建索引,支持模糊查询。
4.空间索引
用于空间数据类型的索引,可以优化空间计算。
5.聚集索引
索引结构和数据结构相结合,只能有一个聚集索引。
如何设计合理?
1.明确索引需求
分析查询语句和业务场景,确定需要创建索引的列,以优化查询性能。
2.选择索引列
选择区分度高、查询频繁的列作为索引列。避免冗余和相关列的索引。
3.选择索引类型
根据查询方式选择合适的索引类型,如B树索引、哈希索引、全文索引等。
4.考虑索引维护开销
写入操作会增加索引维护开销。权衡查询优化与维护成本。
5.设计联合索引
多个列的联合索引可以覆盖更多查询,但要注意索引列顺序。
6.删除不必要索引
清理冗余和未使用的索引,减少维护损耗。
7.关注索引统计信息
分析索引的使用情况,优化设计。
8.测试查询效果
不同场景测试索引设计的查询性能,验证索引有效性。
常见不生效场景
1.全表扫描
SQL语句中没有对索引列进行过滤条件限定,导致全表扫描,索引不生效。
下面是一个全表扫描导致索引失效的例子:
CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(50),age INT, KEY idx_age (age)
);SELECT * FROM users WHERE name = 'John';
上面创建了users表,并在age列上创建了索引idx_age。但在查询时,条件是name列,而没有使用索引列age进行限定,这会导致全表扫描,idx_age索引不会生效。如果查询改为:
SELECT * FROM users WHERE age = 30 AND name = 'John';
先用索引列age进行过滤,再联合name一起查找,这样可以利用到idx_age索引,避免全表扫描,提高查询效率。
2.索引列计算
对索引列进行算数运算、函数转换、类型转换等,结果索引不再生效。
下面是一个索引列计算导致索引失效的例子:
CREATE TABLE users (id INT PRIMARY KEY,age INT, KEY idx_age (age)
);SELECT * FROM users WHERE age + 3 = 33;
上面在age列上创建了索引idx_age。但查询条件中对age进行了计算,将age+3进行比较。这导致索引idx_age无法起到作用。因为计算后age的值已经改变,无法直接用于索引查找。改写为不计算age的形式:
SELECT * FROM users WHERE age = 30;
直接比较age的值,这样可以充分利用idx_age索引,避免表扫描,提高查询效率。
3.模糊查询未用前置匹配
like语句的模糊匹配没有用%放在查询条件后面,索引的优势无法利用。
下面是一个模糊查询未用前置匹配导致索引失效的例子:
CREATE TABLE users (id INT PRIMARY KEY,name VARCHAR(50),KEY idx_name (name)
);SELECT * FROM users WHERE name LIKE '%John';
上面在name列上创建了索引idx_name。但模糊查询中,使用了%John方式,没有指明前置匹配。这种情况下,idx_name索引很难发挥作用,执行会变成全表扫描。改为使用前置匹配的形式:
SELECT * FROM users WHERE name LIKE 'John%';
指明 name 以John开头的条件,这样可以利用索引idx_name进行前置匹配优化,避免全表扫描。
4.复合索引条件次序错误
复合索引的条件没有按索引建立的顺序使用,导致部分索引无法生效。
下面是一个复合索引条件次序错误导致部分索引失效的示例:
CREATE TABLE users (id INT PRIMARY KEY, last_name VARCHAR(50),first_name VARCHAR(50),KEY idx_name (last_name, first_name)
);SELECT * FROM users WHERE first_name = 'John' AND last_name = 'Smith';
上面在last_name和first_name上创建了复合索引idx_name。但是查询条件的顺序是first_name在前,last_name在后。这与索引次序相反,导致索引只能生效于first_name条件,但无法生效于last_name条件。如果调整查询为:
SELECT * FROM users WHERE last_name = 'Smith' AND first_name = 'John';
保持与索引次序一致,那么idx_name索引可以完全生效,避免表扫描,提高查询效率。
5.or条件索引无效
or条件使得索引无法正确限定范围,无法利用索引进行筛选。
or条件导致索引失效的示例如下:
CREATE TABLE users (id INT PRIMARY KEY,age INT, name VARCHAR(50),KEY idx_age (age),KEY idx_name (name)
);SELECT * FROM users WHERE age = 30 OR name = 'John';
上面在age和name列上分别创建了单列索引。但是查询条件使用了or进行连接,这导致索引无法正确限定范围进行过滤。因为age=30的记录和name='John’的记录可能是两组没有交集的记录。使用or时就需要扫描更大范围,索引效率下降。可以改写为:
SELECT * FROM users WHERE age = 30
UNION
SELECT * FROM users WHERE name = 'John';
将or拆分为两个查询语句,每个查询只有一个条件,可以独立利用原有的索引,避免全表扫描。所以or条件往往会导致合理利用不到索引,需要特别注意。
6.子查询或关联查询inner side未用索引
子查询或关联查询的内层查询没有用到合的索引。
一个子查询或者关联查询inner side未使用索引导致外层索引失效的示例如下:
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE order_date = '2020-01-01'
);
外层查询在users表上根据id进行了索引查询。但是子查询orders表的查询没有使用索引,会全表扫描orders表来做IN查询。这会导致外层users表的id索引无效。可以这样修改:
SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders WHERE order_date = '2020-01-01'INDEX (order_date)
);
在子查询orders表查询中,添加order_date列的索引,这样子查询可以利用索引进行筛选。外层的id索引也随之生效,避免全表扫描users表。所以要注意嵌套查询的内层查询也要注意索引的使用,否则容易导致外层索引失效。
7.数据分布严重不均匀
当索引列数据分布严重不均匀时,比如大量重复数据,索引效率会下降。
数据分布不均匀导致索引失效的一个典型例子如下:
CREATE TABLE users (id INT PRIMARY KEY,gender CHAR(1) DEFAULT 'm',KEY idx_gender (gender)
);INSERT INTO users(id) VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10);
上面在gender列创建了索引idx_gender。但是数据插入时,gender列都是默认值’m’,分布完全不均匀。此时如果查询:
SELECT * FROM users WHERE gender = 'm';
索引idx_gender实际上无法生效,因为几乎全表数据都匹配条件。会走全表扫描,而无法利用到索引的优点。这种数据分布极不均匀的情况下,对应的索引效果会大打折扣。要避免这种情况,应该在创建索引时注意对应数据的分布情况,对已存在索引的表也要定期分析数据分布,避免索引失效。
8.返回未命中索引覆盖字段
查询需要返回的字段没有完全被复合索引覆盖。
一个复合索引覆盖字段未命中导致索引失效的示例如下:
CREATE TABLE users (id INT PRIMARY KEY,last_name VARCHAR(50),first_name VARCHAR(50),age INT,KEY idx_name_age (last_name, first_name, age)
);SELECT id, last_name FROM users WHERE last_name='Smith';
这里在last_name,first_name和age上创建了复合索引idx_name_age。查询语句的where条件可以利用这个复合索引。但是SELECT返回的字段id和last_name不完全被idx_name_age索引覆盖。这种情况下,查询还是需要回表去寻找id字段的数据,idx_name_age索引就未能完全生效。解决方法是创建覆盖需要返回的所有字段的索引:
CREATE INDEX idx_name_id ON users (last_name, first_name, id);
或者将查询需要的所有字段都放入复合索引中。所以复合索引的字段覆盖也需要注意,否则索引的利用效率会大打折扣。
9.索引统计信息没有及时更新
导致查询优化器误判查询成本,选择了非最优索引。
示例如下:
CREATE TABLE users (id INT PRIMARY KEY,age INT, phone VARCHAR(15),KEY idx_age(age),KEY idx_phone(phone)
);INSERT INTO users VALUES
(1, 35, '13800000000'),
(2, 40, '13800000001'),
(3, 25, '13800000002');ANALYZE TABLE users; -- 统计信息默认采样扫描表EXPLAIN SELECT * FROM users WHERE age = 40;
开始我们对users表做analyze,收集表的统计信息,包括索引的基数估算等。但analyze默认就是对表做抽样扫描,如果表数据发生大量变更,索引统计信息就会失效。explain显示的结果可能是based on idx_phone, 而不是最优的idx_age索引。这就导致了选择错误索引的问题。解决方法是及时收集更新统计信息:
ANALYZE TABLE users UPDATE INDEXES;
或者在重要SQL语句前强制绑定使用的索引:
SELECT * FROM users FORCE INDEX(idx_age) WHERE age = 40;
所以及时更新统计信息和合理使用optimizer hints都可以避免这类问题。
总结
了解索引的机制和原理,合理设置索引,可以使查询效率大大提升,从而提升后端的运行效率
写在最后
感谢您的支持和鼓励! 😊🙏
如果大家对相关文章感兴趣,可以关注公众号"架构殿堂",会持续更新AIGC,java基础面试题, netty, spring boot, spring cloud等系列文章,一系列干货随时送达!
相关文章:

聊聊MySql索引的类型以及失效场景
文章目录 概念常见的索引1.B树索引2.哈希索引3.全文索引4.空间索引5.聚集索引 如何设计合理?1.明确索引需求2.选择索引列3.选择索引类型4.考虑索引维护开销5.设计联合索引6.删除不必要索引7.关注索引统计信息8.测试查询效果 常见不生效场景1.全表扫描2.索引列计算3.…...

零代码编程:用ChatGPT批量调整文件名称中的词汇顺序
文件夹里面很多文件,需要批量挑战标题中的一些词组顺序:“Peppa Pig - Kylie Kangaroo (14 episode _ 4 season) [HD].mp4”这个文件名改成“14 episode _ 4 season _ Peppa Pig - Kylie Kangaroo.mp4”,可以在ChatGPT中输入提示词࿱…...

stm32 hal库 st7789 1.54寸lcd
文章目录 前言一、软件spi1.cubemx配置2.源码文件 二、硬件spi1.cubemx配置2.源码文件3.小小修改 总结 前言 1.54寸lcd 240*240 一、软件spi 1.cubemx配置 一定要注意把这几个东西上拉。 使用c8 2.源码文件 我使用的是中景园的源码,他本来是是标准库的稍微修改…...

【arm实验1】GPIO实验-LED灯的流水亮灭
linuxlinux:~/study/01-asm$ cat asm-led.S .text .global _start _start: 1.设置GPIOE寄存器的时钟使能 RCC_MP_AHB4ENSETR[4]->1 0x50000a28 LDR R0,0X50000A28 LDR R1,[R0] 从r0为起始地址的4字节数据取出放在R1 ORR R1,R1,#(0x1<<4) 第4位设置为1 ORR R…...

MySQL关联数据表操作方式
1、准备工作(创建数据表) create table employee( emp_id int primary key, name varchar(20), birth_date date, sex varchar(1), salary int, branch_id int, sup_id int );create table client( client_id int primary key, client_name varchar(20)…...

SMOS数据处理,投影变换,‘EPSG:6933‘转为‘EPSG:4326‘
在处理SMOS数据时,遇到了读取nc数据并存为tif后,影像投影无法改变,因此全球数据无法重叠。源数据的投影为EPSG:6933,希望转为EPSG:4326。 解决代码。 python import os import netCDF4 as nc import numpy as np from osgeo impo…...

游戏服务端性能测试实战总结
导语:近期经历了一系列的性能测试,涵盖了Web服务器和游戏服务器的领域。在这篇文章中,我将会对游戏服务端所做的测试进行详细整理和记录。需要注意的是,本文着重于记录,而并非深入的编程讨论。在这里,我将与…...

塔望食观察 | 中国海参产业发展现状及挑战
海参,一个古老的物种,堪称海底活化石,据资料显示,海参在地球上存活超过6亿年,比恐龙还早。海参的药用、食疗和营养滋补价值极高,清朝学者赵学敏编的《本草纲目拾遗》有这样的叙述:“海参性温补&…...

springboot 捕获特点异常信息并处理
前端获取效果图 springboot 捕获特点异常信息并处理 import com.one.utils.JSONResult; //JSONResult定义处理结果对象 import org.springframework.web.bind.annotation.ExceptionHandler...

【Spring框架学习3】Spring Bean的作用域 及 生命周期
一、Spring Bean的作用域有哪些? Spring框架支持以下五种Bean的作用域: Singleton:这是默认的作用域,在每个Spring IoC容器中只有一个Bean的实例(IoC初始化后)。Spring 中的 bean 默认都是单例的,是对单例设计模式的…...

多线程并发篇---第四篇
系列文章目录 文章目录 系列文章目录一、Java中synchronized 和 ReentrantLock 有什么不同?二、有三个线程T1,T2,T3,如何保证顺序执行?三、SynchronizedMap和ConcurrentHashMap有什么区别?一、Java中synchronized 和 ReentrantLock 有什么不同? 相似点: 这两种同步方式有…...

vs code 添加vue3代码模板方法
最终效果 vs code 添加vue文件模板用于通过简写自动生成代码 操作步骤如下 1.找到vue模板代码编写入口 2.修改模板内容 2.1 vue.json内容 {// Place your snippets for vue here. Each snippet is defined under a snippet name and has a prefix, body and// description. T…...

怎么通过Fiddler对APP进行抓包?以及高级应用场景分析
前言 我们经常需要用到Fiddler做代理服务器对Web、APP应用进行抓包,以便我们对接口功能进行测试调试,定位问题等。这篇将讲述怎么通过Fiddler对APP进行抓包,以及简单介绍一些高级应用场景。 首先,附上Fiddler使用的环境配置清单…...

centos下安装配置redis7
1、找个目录下载安装包 sudo wget https://download.redis.io/release/redis-7.0.0.tar.gz 2、将tar.gz包解压至指定目录下 sudo mkdir /home/redis sudo tar -zxvf redis-7.0.0.tar.gz -C /home/redis 3、安装gcc-c yum install gcc-c 4、切换到redis-7.0.0目录下 5、修改…...

【angular】TodoList小项目(已开源)
参考:https://segmentfault.com/a/1190000013519099 文章目录 准备工作headerTodo、Doing、Done样式(HTMLCSS)功能(TS)将输入框内容加入todoList(addTodo)将todo事件改到doing 服务 参考开源 效…...

【Java 进阶篇】HTML块级元素详解
HTML(Hypertext Markup Language)是用于创建网页的标记语言。在HTML中,元素被分为块级元素和内联元素两种主要类型。块级元素通常用于构建网页的结构,而内联元素则嵌套在块级元素内,用于添加文本和其他内容。本文将重点…...

CSS设置鼠标样式和添加视频样式
鼠标的样式 <div style"cursor: default">默认鼠标的样式</div><div style"cursor: pointer">小手样式</div><div style"cursor: move">移动样式</div><div style"cursor: text">文本样式&…...

项目文件上传到行云codeup teambition
接手公司好几年的老项目,在行云上已经有1.9G的大小所以被限制上传了 只有花钱扩容或者重新建库。 1.重新建库:登录你的行云账户在代码库中新建代码库(网上有详细的) 创建成功后的库中只有readme文件。 2.复制代码库的下载地址 …...

现货黄金和实物黄金有什么区别?
在黄金投资市场中,现货黄金和实物黄金都是两种比较受欢迎的黄金投资品种。想想越来越多人认识到黄金投资的重要性,那么要选择一个投资品种,应该选哪个黄金投资品种呢?下面我们就来讨论一下这两者有何区别,以及投资者应…...

/dev下没有video0这个文件(ubuntu无法打开摄像头)
文章目录 硬件问题一、查看虚拟机摄像头连接情况二、解决红色报错三、虚拟机硬件处理内容问题一、设备号二、视频格式问题硬件问题 一、查看虚拟机摄像头连接情况 报错详情 ERROR: cannot launch node of type [image_view/image_view]: image_view ROS path [0]=/opt/ros/m…...

mysql面试题32:MySQL数据库服务器性能分析的方法命令有哪些?
该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:MySQL数据库服务器性能分析的方法命令有哪些? MySQL数据库服务器性能分析的方法和命令有以下几种: EXPLAIN命令:用于分析查询语句的执行计划,…...

伦敦银最新价格能进吗?
不少新手的伦敦银投资者由于看不懂行情走势,在行情机会来临时总感觉患得患失,但由于又十分渴望在这个市场上实现收益,所以经常通过各种各样的方式方法和手段,希望行情走势什么时候会出现进场的机会。 可以肯定的是,伦敦…...

【计算机毕设案例推荐】洋州影院购票管理系统SpringBoot+Vue
前言:我是IT源码社,从事计算机开发行业数年,专注Java领域,专业提供程序设计开发、源码分享、技术指导讲解、定制和毕业设计服务 项目名 基于SpringBoot的洋州影院购票管理系统 技术栈 SpringBootVueMySQLMaven 文章目录 一、洋州…...

Java设计模式之模板方法模式
模板方法模式(Template Method Pattern)是一种行为型设计模式,它定义了一个算法骨架,将一些步骤的具体实现延迟到子类中。模板方法模式通过将共同的代码逻辑放在父类中,而将具体的实现细节留给子类来实现,从…...

MinIO的安装与使用
文章目录 1.MINIO是什么?2.MINIO安装3.启动脚本4.打开MINIO页面5.MC命令6.MINIO备份脚本 1.MINIO是什么? MinIO 是一款高性能、分布式的对象存储系统. 它是一款软件产品, 可以100%的运行在标准硬件。即X86等低成本机器也能够很好的运行MinIO。 MinIO与…...

“==”和equals的区别
总结几句话: 双等号始终是 1.基本数据类型:比较存储的值是否相等。 2.引用数据类型:比较所指对象的地址值是否相等。 equals 1.没有被重写过: 相当于;但是不能比较基本数据类型,比较的是引用对象的所指…...

QT - 对话框去掉标题栏问号
要去掉 Qt 对话框的标题栏上的问号图标,你可以使用 Qt::CustomizeWindowHint 标志来定制对话框的窗口样式。 以下是一个示例代码,演示如何去掉标题栏上的问号图标: #include <QDialog> #include <QDialogButtonBox> #include &…...

FPGA---UDP通信求助
项目场景: 使用UDP进行回环,网络调试助手,发送数据通过UDP接收模块接收,解析出数据,给到UDP发送模块,传回上位机。 问题描述 UDP接收模块中,接收到的CRC校验值与自己计算CRC校验值进行判断&am…...

RxJava介绍及基本原理
随着互联网的迅猛发展,Java已成为最广泛应用于后端开发的语言之一。而在处理异步操作和事件驱动编程方面,传统的Java多线程并不总是最佳选择。这时候,RxJava作为一个基于观察者模式、函数式编程和响应式编程理念的库,为我们提供了…...

nginx目录穿越
测试nginx版本为nginx/1.23.3 location /file {alias /home/;} 在/usr跟目录下新建a.txt测试文件 通过访问 http://{ip}:{端口}/file../test.txt 实现目录穿越 防护:location与alias的值都加上/或不加/...