聊聊MySql索引的类型以及失效场景

news2024/11/13 21:59:54

文章目录

      • 概念
      • 常见的索引
        • 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.索引统计信息没有及时更新
      • 总结
      • 写在最后

579a429daf314744b995f37351b46548

概念

索引是数据库管理系统中一个重要的优化结构,目的是提高数据库查询和操作的速度。

索引的工作原理是对数据库表中的一列或多列的值进行预排序,然后存储该列值与数据行的地址映射,在查询时可以直接查找到数据,而无需全表扫描。


常见的索引

image-20231011135654419

1.B树索引

最常见的索引类型,可以对一个或多个列创建索引。

2.哈希索引

通过哈希函数直接定位到数据行。查找速度极快,但只支持等值查询。

3.全文索引

可以对文本中的关键词创建索引,支持模糊查询。

4.空间索引

用于空间数据类型的索引,可以优化空间计算。

5.聚集索引

索引结构和数据结构相结合,只能有一个聚集索引。


如何设计合理?

image-20231011143716629

1.明确索引需求

​ 分析查询语句和业务场景,确定需要创建索引的列,以优化查询性能。

2.选择索引列

​ 选择区分度高、查询频繁的列作为索引列。避免冗余和相关列的索引。

3.选择索引类型

​ 根据查询方式选择合适的索引类型,如B树索引、哈希索引、全文索引等。

4.考虑索引维护开销

​ 写入操作会增加索引维护开销。权衡查询优化与维护成本。

5.设计联合索引

​ 多个列的联合索引可以覆盖更多查询,但要注意索引列顺序。

6.删除不必要索引

​ 清理冗余和未使用的索引,减少维护损耗。

7.关注索引统计信息

​ 分析索引的使用情况,优化设计。

8.测试查询效果

​ 不同场景测试索引设计的查询性能,验证索引有效性。


常见不生效场景

image-20231011143952193

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等系列文章,一系列干货随时送达!

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

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

相关文章

容器轻松上阵,优雅下线才是胜负之道

概述 优雅关闭: 在关闭前,执行正常的关闭过程,释放连接和资源,如我们操作系统执行shutdown。 目前业务系统组件众多,互相之间调用关系也比较复杂,一个组件的下线、关闭会涉及到多个组件。 对于任何一个线…

(2022|NIPS,CogLM,分层,LoPAR,icetk)CogView2:通过分层 Transformer 更快更好地文本到图像生成

CogView2: Faster and Better Text-to-Image Generation via Hierarchical Transformers 公众号:EDPJ(添加 VX:CV_EDPJ 或直接进 Q 交流群:922230617 获取资料) 目录 0. 摘要 1. 简介 2. 相关工作 3. 方法 3.…

基于SpringBoot+Vue的教师人事档案管理系统

1 简介 基于SpringBootVue的教师人事档案管理系统,教师人事档案管理系统利用信息的合理管理,动态的、高效的、安全的实现了教师的各种需求,改变了传统的网上查看方式,使教师可以足不出户的在线查看最适合自己个人档案、奖惩信息、…

百度一面:谈谈 @Transactional 的原理和坑

百度一面:谈谈 Transactional 的原理和坑 这篇文章,会先讲述 Transactional 的 4 种不生效的 Case,然后再通过源码解读,分析 Transactional 的执行原理,以及部分 Case 不生效的真正原因。 项目准备 下面是 DB 数据和…

js的BoM事件(二)

js的BoM事件&#xff08;二&#xff09;&#xff0c;上一篇的补充 一.alert,confirm二.prompt三.open四.close 一.alert,confirm 实例&#xff1a; alert(hi); confirm(message);二.prompt <body><button ></button><script>var btndocument.querySe…

dbeaver 插入别名设置禁用

1&#xff0c;前提 最近换了一个数据库连接工具&#xff0c;初次使用&#xff0c;非常别扭。 2&#xff0c;问题 首先遇到的第一个问题是 每次输入from table时&#xff0c;后面就会自动添加一个表别名 tt&#xff0c;然后语句就变成这样 from table tt &#xff0c;所以每次…

全面深入了解自动化测试

一、自动化测试 在软件测试中&#xff0c;自动化测试指的是使用独立于待测软件的其他软件来自动执行测试、比较实际结果与预期并生成测试报告这一过程。在测试流程已经确定后&#xff0c;测试自动化可以自动执行的一些重复但必要测试工作。也可以完成手动测试几乎不可能完成的…

飞凌嵌入式受邀参加「NXP创新技术论坛」

2023年10月10日&#xff0c;「NXP创新技术论坛」在深圳湾万丽酒店举行&#xff0c;飞凌嵌入式作为NXP金牌合作伙伴受邀参加此次论坛&#xff0c;与众多智能工业行业的伙伴深入交流市场趋势与行业洞察&#xff0c;共同促进未来市场的发展。 本次论坛&#xff0c;飞凌嵌入式展示了…

GaussDB向量数据库为盘古大模型再添助力

在今年7月7日的华为开发者大会2023(Cloud)期间,华为云盘古大模型3.0正式发布。目前盘古大模型已在政务、金融、制造、医药研发、气象等诸多行业发挥巨大价值。此次华为云发布的GaussDB向量数据库,具备一站式部署、全栈自主创新优势,不仅如此,它的ANN算法在行业排名第一,…

龙讯旷腾:如何建立基于第一性原理的正向研发模式,原子级计算伴随的时间和空间尺度增长将带来的变革

2023年10月8-11日&#xff0c;由中国材料研究学会主办的第四届中国新材料产业发展大会在浙江温州隆重举行。来自全国各地的6000余名新材料专家、企业家、投资家、当地高等院校和企事业单位的代表以及51位两院院士出席了本次大会。龙讯旷腾总经理吕海峰特邀做“先进材料数字化研…

点击、拖曳,15分钟搞定BI零售数据分析

早几年做数据分析还很依赖IT&#xff0c;过程复杂、耗时长、灵活性差&#xff0c;但这几年随着BI智能数据分析技术的成长&#xff0c;零售数据分析发生了翻天覆地的变化&#xff0c;其中最直观的一点就是&#xff1a;点击、拖曳&#xff0c;15分钟内就能搞定BI零售数据分析。 …

uCOSIII实时操作系统 五 任务API(任务创建和删除)

任务创建和删除 引入&#xff1a;一个任务的三要素是任务主体函数&#xff0c;任务栈&#xff0c;任务控制块&#xff0c;那么怎样吧这个三要素联系在一起呐&#xff1f; 任务创建&#xff1a; 在UCOSIII中我们通过函数OSTaskCreate()来创建任务。 作用&#xff1a;任务控制块…

有root权限的共享服务器,返现福利

以下是目前各类型服务器配置与价格目录&#xff1a; 可咨询文末微信号领取返现福利&#xff0c;注册链接&#xff1a; 西柚云超算https://www.xiyoucloud.net/aff/YADJJHWA 微信号&#xff1a;生信小博士

需求解析思路

需求&#xff1a;如果一个学生N天没学习了 根据question_user_submit_record&#xff08;N配置&#xff09;&#xff0c;公众号推送通知到java8c.com学习 由于写代码需要严谨快速&#xff1a; 当前写代码方式&#xff1a;先写controller&#xff0c;再写sql语句&#xff0c;…

Postman历史版本下载

1. 下载对应版本的postman 历史版本下载 请把下面链接的"版本号"替换为指定的版本号&#xff0c;例如&#xff1a;8.8.0 Windows64位 ​https://dl.pstmn.io/download/version/版本号/win64​ Windows32位 https://dl.pstmn.io/download/version/版本号…

SpringBoot+Dubbo+Nacos 开发Demo

1、是什么 Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架&#xff0c;使得应用可通过高性能的RPC实现服务的输出和输入功能&#xff0c;可以和Spring框架无缝集成。Dubbo是一款高性能、轻量级的开源Java RPC框架&#xff0c;它提供了三大核心能力&#xff1a;面向接口的…

MinIO的安装与使用

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

智能导诊系统、智能在线问诊系统源码

一、需求背景 目前各大城市的著名医院吸引越来越多的患者&#xff0c;咨询台的服务需求也随之增加。医院虽然设置了少数咨询台&#xff0c;但由于患者人数众多&#xff0c;咨询台往往无法满足患者咨询要求&#xff0c;护士工作量巨大&#xff0c;医院巨大的规模也让咨询台数量…

佳音通讯400电话中心:在线自选,惠及企业

在当今竞争激烈的商业环境中&#xff0c;企业需要提供卓越的客户服务来脱颖而出。而一个高效的400电话中心则成为了越来越多企业的选择。佳音通讯400电话中心官方网站是企业选择400电话服务的首选平台&#xff0c;提供了在线自选功能&#xff0c;让企业能够根据自身需求灵活选择…

实现一个自己的脚手架教程

前言 脚手架并不实现&#xff0c;难的是最佳实践的整理和沉淀。本文不会涉及到最佳实践方面的内容&#xff0c;只是教会你如何实现一个最基础的脚手架&#xff0c;以此作为展示最佳实践的载体。 如何搭建一个脚手架的工程 如何开发和调试一个脚手架 脚手架中如何接收和处理命…