当前位置: 首页 > news >正文

八股学习(三)---MySQL

一、MySQL中的回表是什么?

我的回答:

MySQL回表指的是在查询使用非聚簇索引也就是二级索引时,叶子节点只存储了索引列的值和主键Id,若要查询其他字段,就要根据主键去聚簇索引查询完整的数据。这个过程就是回表。比如用name的二级索引查age,要先通过name找到主键id,再用这个主键id查询age。回表会增加 IO ,所以可以建立覆盖索引来包含所需要的字段,避免回表。我练过用联合索引包含其他字段,减少了回表,查询快了不少~

回答重点(官方答案):

“回表” 是指在使用二级索引(非聚簇索引)作为条件进行查询时,由于二级索引中只存储了索引字段的值和对应的主键值,无法得到其它数据。如果要查询数据行中的其它数据,需要根据主键去聚簇索引查找实际的数据行,这个过程被称为回表。

二、MySQL中使用索引一定有效吗?如何排查索引效果?

我的回答:

MySQL中使用索引不一定有效,比如索引字段上有函数运算、使用了like '%xxx'这类前缀模糊匹配查询、类型不匹配,或者统计信息不准确等, 都可能导致索引失效。

排查索引效果,我们可以使用explain分析SQL执行计划,重点看type字段,(如all表示全表扫描)、key字段(是否为null),以及rows估算值

再通过show status like ‘Handler%’; 查看索引使用次数,对比查询前后的Handler_read_key和Handler_read_rnd_next等指标。之前我在练习时,发现一条SQL有索引,但是执行慢,用explain发现是因为对索引字段做了函数操作,调整后索引生效,查询效率显著提升,所以现在写SQL后都会习惯性用这些方法检验索引效果,避免出校“有索引但不生效”的情况。

回答重点(官方答案):

索引不一定有效。
例如查询条件中不包含索引列、低基数列索引效果不佳,或查询条件复杂且不匹配索引的顺序。
对于一些小表,MySQL 可能选择全表扫描而非使用索引,因为全表扫描的开销可能更小。
最终是否用上索引是根据 MySQL 成本计算决定的,评估 CPU 和 I/O 成本最终选择用辅助索引还是全表扫描。有时候确实是全表扫描成本低所以没用上索引。但有时候由于一些统计数据的不准确,导致成本计算误判,而没用上索引。

排查索引效果的方法:使用 EXPLAIN 命令,通过在查询前加上 EXPLAIN ,可以查看 MySQL 选择的执行计划,了解是否使用了索引、使用了哪个索引、估算的行数等信息。
主要观察 EXPLAIN 结果以下几点:

  • type(访问类型):这个属性显示了查询使用的访问方法,例如 ALL 、index 、range 等。当查询使用索引时,这个属性通常会显示为 index 或 range ,表示查询使用了索引访问。如果这个值是 ALL ,则表示查询执行了全表扫描,没有使用索引。
  • key(使用的索引):这个属性显示了查询使用的索引,如果查询使用了索引,则会显示索引的名称。如果这个值是 NULL ,则表示查询没有使用索引。
  • rows(扫描的行数):这个属性显示了查询扫描的行数,需要评估下扫描量。

扩展知识


确定索引真的生效了吗?
索引失效的场景有很多,也是面试官经常喜欢问的,可以根据具体场景进行排查,典型场景可以分为以下几点(实际索引的选择会根据 mysql 优化器的成本评定,答案最后会提到):

  1. 使用了联合索引却不符合最左前缀
    举个例子:小鱼对 user 表建立了一个联合索引为 name_age_id 的联合索引。
    他使用以下 SQL 查询 select * from user where age = 10 and id = 1;
    这样的写法恰恰不满足最左前缀原则,索引就失效啦。

  2. 索引中使用了运算
    例如这个 SQL select * from user where id + 3 = 8 。这样会导致全表扫描计算 id 的值再进行比较,使得索引失效。

  3. 索引上使用了函数也会失效
    例如:select * from user where LOWER (name) like 'cong%'; 。
    这样也会导致索引失效,索引参与了函数处理,会导致去全表扫描。

  4. like 的随意使用
    例如:select * from user where name like '% cong%'; 因为索引是从左到右来进行排序查找的,占位符直接放在了最左边开头,可能会导致直接全表扫描,这种情况就会导致索引失效。

  5. or 的随意使用
    user 当前只有一个索引 name 。此时执行以下 SQL:
    select * from user where name = 'cong' or age = 18; 这可能也会导致索引失效,因为 age 没有索引。

  6. 随意的字段类型使用
    不小心将 varchar 类型的 name 条件匹配了 int 类型字段。SQL 是这样的 select * from user where name = 1; ,在代码中涉及隐式转换!等于 select * from user where CAST (name AS signed int) = 1; ,这就变成了第三条索引上使用了函数,导致索引失效。
    除此之外还有隐式字符编码转换的问题,即联表查询的时候,如果不同表之间的关联字段字符编码不一致,也会导致隐式转换编码,等于变相用上了函数,使得索引失效。

  7. 不同的参数也会导致索引失效
    这个就是我在回答重点里面说的 “是否用上索引是根据 MySQL 成本计算决定的”。不同的参数 MySQL 评估成本不一致,有时候会选择使用索引,有时候会选择全表扫描,特别是在复杂查询(联表、子查询、需要回表等)的情况下。

比如根据商品从订单表查询,收集商品对应的所有买家的订单信息。如果传入的商品 id 是个热点商品,占据这家店铺 80% 的销量,那么本次查询对订单表很可能是全表查询,如果是冷门商品,则很可能是走索引查询。
8) 表中两个不同字段进行比较
例如这样的 SQL : select * from user where id > age; ,将 id 跟 age 字段做了比较,索引失效。
9) 使用了 order by
当 order by 后面跟的不是主键或者不是覆盖索引会导致不走索引。
为什么索引生效了反而查询变慢了呢?
确认是否选对了索引!MySQL 根据优化器会评估成本选择对应的索引,但有时候 MySQL 因为估计值不准确,导致选错了索引,因此查询速度反而更慢。

三、在MySQL中建立索引时需要注意哪些事项?

我的回答:

我会注意:

1.按需创建索引:根据实际查询需求,在where,join,order by等子句的字段上建索引,避免冗余。

2.会优先给唯一性高的,如id、手机号建立索引,像性别低选择性字段建立索引意义不大。

3.若是联合索引,遵循最左前缀原则,把选择性高的字段放在前面,比如(a,b,c)的索引能支持a、a+b、a+b+c的查询

4.避免失效场景,不在字段上使用函数,避免使用like %xxx、保证类型匹配,防止索引失效

5.权衡性能:索引会加快查询,但是会降低增删改的速度,还会占用磁盘空间,因此写入频繁的表要控制索引数量。

我练习的时候,给订单表的user_id 和 create_time建立联合索引,发现遵循最左原则的查询能命中索引,但是加了低选择性的status字段后反而失效,删除后性能恢复了,这让我明白索引设计要结合实际场景,不能盲目添加。

类型匹配解释:

加了低选择性的status字段,索引失效解释:

重点回答(官方答案)

  1. 不能盲目建立索引,索引并不是越多越好,索引会占用空间,且每次修改的时候可能都需要维护索引的数据,消耗资源。

  2. 对于字段的值有大量重复的不要建立索引。比如说:性别字段,在这种重复比例很大的数据行中,建立索引也不能提高检索速度。但是也不绝对,例如定时任务的场景,大部分任务都是成功,少部分任务状态是失败的,这时候通过失败状态去查询任务,实际上能过滤大部分成功的任务,效率还是可以的。

  3. 对于一些长字段不应该建立索引。比如 text、longtext 这种类型字段不应该建立索引。因为占据的内存大,扫描的时候大量加载至内存中还耗时,使得提升的性能可能不明显,甚至可能还会降低整体的性能,因为别的缓存数据可能因为它被踢出内存,下次查询还需要从磁盘中获取。

  4. 当数据表的修改频率远大于查询频率时,应该好好考虑是否需要建立索引。因为建立索引会减慢修改的效率,如果很少的查询较多的修改,则得不偿失。

  5. 对于需要频繁作为条件查询的字段应该建立索引。在 where 关键词后经常查询的字段,建立索引能提高查询的效率,如果有多个条件经常一起查询,则可以考虑联合索引,减少索引数量。

  6. 对经常在 order by、group by、distinct 后面的字段建立索引。这些操作通常需要对结果进行排序、分组或者去重,而索引可以帮助加快这些操作的速度。

扩展知识

MySQL 索引的最左前缀匹配原则是什么?

回答重点


MySQL 索引的最左前缀匹配原则指的是在使用联合索引时,

查询条件必须从索引的最左侧开始匹配。如果一个联合索引包含多个列,查询条件必须包含第一个列的条件,然后是第二个列,以此类推。
底层原理:因为联合索引在 B+ 树中的排列方式遵循 “从左到右” 的顺序,例如联合索引 (first_name, last_name, age) 会按照 (first_name, last_name, age) 的顺序在 B+ 树中进行排序。
MySQL 在查找时会优先使用 first_name 作为匹配依据,然后依次使用 last_name 和 age 。因此,组合索引能够从左到右依次高效匹配,跳过最左侧字段会导致无法利用该索引。
按照 (first_name, last_name, age) 的顺序在 B+ 树中的排列方式 (大致的示意图) 如下

http://www.dtcms.com/a/266872.html

相关文章:

  • 高流量发布会,保障支付系统稳定运行感想
  • Flink-05学习 接上节,将FlinkJedisPoolConfig 从Kafka写入Redis
  • 关于python
  • Javaweb - 10.2 Servlet
  • 【51单片机倒计时选位最右侧2位显示秒钟后最左侧1位显示8两秒后复位初始状态2个外部中断组合按键功能】2022-7-5
  • 数据库位函数:原理、应用与性能优化
  • Nuxt 3 面试题合集(中高级)
  • 在 C++ 中,判断 `std::string` 是否为空字符串
  • 【贪心】P2660 zzc 种田
  • Rust 中的返回类型
  • 指数分布的Python计算与分析
  • 微服务架构下的抉择:Consul vs. Eureka,服务发现该如何选型?
  • 简单 Python 爬虫程序设计
  • 递推|递归|分治
  • Python 办公实战:用 python-docx 自动生成 Word 文档
  • 【ROS2 自动驾驶学习】01-工具链的安装
  • 过滤器应用
  • MySQL分布式ID冲突详解:场景、原因与解决方案
  • Hive UDF 开发实战:MD5 哈希函数实现
  • 每周资讯 | Krafton斥资750亿日元收购日本动画公司ADK;《崩坏:星穹铁道》新版本首日登顶iOS畅销榜
  • 只出现一次的数字2
  • 暴雨服务器成功中标华中科技大学集成电路学院服务器采购项目
  • HarmonyOS免密认证方案 助力应用登录安全升级
  • 使用 DigitalPlat 免费搭配 Cloudflare Tunnel 实现飞牛系统、服务及 SSH 内网穿透教程
  • 计算机视觉---RealSense深度相机技术
  • 【C++类和对象解密】面向对象编程的核心概念(中)
  • Android Studio-Git的使用指南
  • 金融平衡术:创新与合规的突围之路
  • Word和Excel批量转PDF新方法,操作简单
  • 仿muduo库One Thread One Loop式主从Reactor模型实现高并发服务器