mysql是如何选择索引的(为什么会选错索引)

MySQL 中这么多索引,你应该怎么选择呢? 本次我从根本上给你介绍了各种索引的情况。对于单个字段的索引来说,要直接使用,而不能写成一个表达式,写成表达式将会无法命中索引。对于多个字段需要索引来说,一般需要创建组合索引,这样有利于命中索引,但是一定要注意组合索引的前缀性。对于索引的类型,我还给你介绍了唯一索引和普通索引,在读的场景比较多的情况下普通索引和唯一索引都能胜任,不过在写场景比较多的情况下,普通索引的性能要优于唯一索引。在实际应用中,我们通常建议使用普通索引,对于需要唯一的字段,我们一般在代码的层面去控制其唯一性。 阅读详情

什么是查询成本

查询成本 = I/O成本 + CPU成本

I/O 成本:将数据从磁盘加载到内存的损耗时间称为 I/O 成本(对 memory 引擎的表除外,使用与磁盘性的存储引擎,例如 myisam,innodb)

CPU成本:读取记录,检测记录是否满足条件,对结果集进行排序等这些操作的损耗时间称为 CPU 成本

对Innodb 存储引擎来说,读取一个数据页花费的成本默认是 1.0;读取记录、检测记录是否满足条件成本默认是 0.2。这里说的 “1.0” “0.2”,在mysql中是可以设置的

注意:在读取记录时,即使不需要检测记录是否满足条件,或者除了读取操作外没有其他操作,其成本也算作 0.2

基于成本的优化过程

  1. 根据搜索条件,找出所有可能使用的索引
  2. 计算全表扫描的代价
  3. 计算使用不同索引执行查询的代价
  4. 对比各种执行方案的代价,找出成本最低的那个方案

计算全表扫描的代价

代价由两部分组成

  • 聚簇索引占用的页面数
  • 表中的记录数

聚簇索引占用的页面数 = Data_length of show table status like '%TableName%' \ 16KB,mysql默认的一个数据页的大小是 16KB

表中的记录数 = Rows of show table status like '%TableName%'

计算使用不同索引执行查询的代价

代价由两部分组成

  • 索引的扫描区间数量
  • 所有扫描区间需要回表的记录数

注意

  • mysql认为 无论某个扫描区间的二级索引到底占用了多少个页面(数据页),查询优化器粗暴的认为读取一个索引的扫描区间的 I/O 成本与读取一个页面的 I/O 成本是相同的。
  • mysql认为 一次回表操作的成本与读取一个页面的 I/O 成本是相同的

某个扫描区间,回表的记录数的计算过程(这种方式称为 index dive)

为了方便描述,这里假设扫描区间是 10 < a < 1000,字段 a 是索引

  1. 先根据 a > 10 在 a 索引树上找到满足 a > 10 的第一条记录,我们称为“最左记录”
  2. 先根据 a > 1000 在 a 索引树上找到满足 a > 1000 的第一条记录,我们称为“最右记录”
  3. 如果区间的 最左记录 和 最右记录 所在的页面相隔不是太远(在mysql 5.7.22 版本中,只要相隔不大于 10 个页面即可),会从左到右遍历数据页的Page header 中的 PAGE_N_RECS 属性,就可以精确统计出满足 10 < a < 1000 条件的二级索引记录的条数。如果相隔太远,就沿着 最左记录 向右读 10 个页面,计算每个页面平均包含多少记录,然后用这个平均值乘以 最左记录 和 最右记录 之间的页面数量就可以了(最左记录 和 最右记录 之间的页面如何计算,跟 B+树的数据结构有关的,这个后续再讲)

说明:数据页有一个 page header 部分,page header 中有一个名为 PAGE_N_RECS 的属性,该属性代表了该页面中目前有多少条记录

举例:如何计算查询成本

例子1:sql :select * from t where a >10 and a < 100,全表记录为 1000 条,字段 a 是表 t 的非唯一二级索引。

计算全表扫描查询成本

show table status like 't',显示的 Data_length 为 1589248,Rows 为 944

查询成本 = I/O成本 + CPU成本 = 聚簇索引占用的页面数 * 1.0 + 表中的记录数 * 0.2 = 1589248 / 16386 * 1.0 + 944 * 0.2 = 97 + 188.8 = 285.8

计算根据索引 a 进行查询的成本

注意这个例子中,索引 a 的扫描区间只有一个,就是(10,1000)

为了方便计算,这里假设索引 a 的扫描区间 (10,1000),二级索引需要回表的记录数为 89

这里将查询成本,分成两部分计算,一部分是二级索引的查询成本,一部分是回表操作的成本

二级索引的查询成本 = I/O成本 + CPU成本 = 1.0 + 89 * 0.2 = 18.8

回表操作的查询成本 = I/O成本 + CPU成本 = 89 * 1.0 + 89 * 0.2 = 106.8

总的查询成本为 18.8 + 106.8 = 126.8

例子2:sql :select * from t where a in (123,456),全表记录为 1000 条,字段 a 是表 t 的非唯一二级索引。

计算全表扫描查询成本,与例子 1 计算过程一样

计算根据索引 a 进行查询的成本

注意,in 操作,a 索引的扫描区间就是两个,一个是(123),一个是(456)

基于索引统计数据的成本计算

使用 index dive 进行索引查询成本的计算是有条件的,为什么会有条件呢,我们假设一个 select * from t where a in (1,2,3,````),in中的值有 1000 个,也就是有 1000 个扫描区间。那么就可能导致 mysql 在使用 index dive 进行索引查询成本计算的过程耗损可能比全表扫描的查询成本都高。

对此 mysql 引入了一个参数 eq_range_index_dive_limit 用于控制 index dive 的使用方式。默认值为 200,如果索引的扫描区间个数小于 200 个,使用 index dive 方式,否则使用 索引统计数据的方式 进行成本计算

统计数据是如何统计的(概要)

采用“采样统计”的方式统计,InnoDB 默认会选择 N(innodb_stats_persistent_sample_pages 参数控制 N 的大小,默认值为 20) 个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。

而数据表是会持续更新的,索引统计信息也不会固定不变。所以,当变更的数据行数超过 1/M 的时候,会自动触发重新做一次索引统计。

在 MySQL 中,有两种存储索引统计的方式,可以通过设置参数 innodb_stats_persistent 的值来选择:

设置为 on 的时候,表示统计信息会持久化存储。这时,默认的 N 是 20,M 是 10。

设置为 off 的时候,表示统计信息只存储在内存中。这时,默认的 N 是 8,M 是 16。

现在我们看看, select * from t where a in (1,2,3,````) 的索引 a 的查询成本计算

假设 通过 show table status 查看表 t 的 Rows 值为 10000

假设 通过 show index from 查看表 t 的 字段 a 的索引基数(Cardinality )为 987

通过以上两个值,我们可以计算出 索引 a 数据的重复度约等于 10000 / 987 = 10

二级索引的查询成本 = I/O成本 + CPU成本 = 1000 * 1.0 + 1000 * 0.2 = 2400

回表操作的查询成本 = I/O成本 + CPU成本 = 1000 * 10 * 1.0 + 1000 * 10 * 0.2 = 12000

总的查询成本 = 2400 + 12000 = 16000

调节成本常数

server_cost

列说明

cost_name 成本评估的时候用的名字

cost_value 成本评估项的具体值。如果这个值是非NULL的,SQL服务就会使用这个值,否则SQL服务会使用默认值

last_update 该行数据的上次更新时间。

comment 该项评估信息的备注。数据库管理员可以在这一栏写备注,比如为什么要设置这么个值等等。

cost_name 值说明

engine_cost

列说明

cost_name 值说明

MySQL 选错索引的原因? MySQL 中,可以为某张表指定多个索引,但在语句具体执行时,选用哪个索引是由 MySQL 中执行器确定的。那么执行器选择索引的原则是什么,以及会不会出现选错索引的情况呢? 先看这样一个例子: 创建表 Y,设置两个普通索引, 创建一个存储过程用于插入数据。 MySQL: 5.7.27, 隔离级别: RR CREATE TABLE `Y` ( `id` int(11) NOT NU... 阅读详情

相关推荐

STM32驱动AD2S1210实现旋变解码与角度读取

旋转变压器作为一种耐高温、抗振动的角度传感器,在工业伺服、机器人关节和电动汽车电驱等场景中占据重要地位。其输出信号需要经过专用转换芯片处理才能被MCU高效使用。AD2S1210是一款典型的旋变数字转换器(RDC),内部采用Type II型跟踪环,将模拟SIN/COS信号实时解算为数字角度与速度,降低了处理器负担并提升抗干扰能力。本文基于STM32平台,详细介绍了AD2S1210的硬件接线、SPI通信配置、寄存器初始化流程,以及读取位置数据时的SAMPLE脉冲时序等关键实现。同时总结了常见故障如全FF、角度跳

weixin_34194829的博客 196

MYSQL——explain执行计划结果分析

文章目录explain执行计划结果分析0、id1、select_type2、table3、partitions4、type5、possible_keys6、key7、key_len8、ref explain执行计划结果分析 在MySQL中,我们可以通过explain命令查看sql的执行情况。 获取MySQL如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序。 例...

weixin_42924812的博客 1186

Telegram AI Bot自动化实战:5步用Make搭建业务工作台

Telegram Bot 是一种轻量级、高抵达率的消息自动化载体,其核心价值在于将结构化消息(如text、photo、callback_query)转化为可编程的事件流。基于 Bot API 的简洁设计与 Webhook 机制,开发者无需复杂鉴权即可实现毫秒级响应。结合低代码平台 Make,可快速构建具备上下文识别、条件路由、多系统分发与错误熔断能力的自动化流程。该方案特别适用于客服分发、数据同步、IoT告警等高频、规则明确、需即时反馈的业务场景,显著降低对 Python/Node.js 编程与 DevOp

weixin_33158887的博客 301

【13】MySQL如何选择合适的索引?

查询条件:为经常出现在 WHERE、JOIN、ORDER BY 和 GROUP BY 等子句中的列创建索引。列的基数:对于高基数(unique 值多)的列创建索引,而低基数列则不建议创建索引。数据量:大表中的查询需要索引来提高效率,而小表中的索引影响可能不大。查询模式:根据查询的复杂性和使用频率,选择单列索引或复合索引。索引维护:定期检查索引的效果,删除不再需要的索引,避免索引过多带来负担。

qq_35320456的博客 1476

MT6768平台Sensor Bring Up全流程实战:从驱动添加到问题排查(附避坑指南)

本文详细介绍了联发科MT6768平台Sensor Bring Up的全流程实战指南,从驱动添加、硬件配置到问题排查,提供了全面的避坑建议。内容涵盖环境准备、驱动文件集成、硬件接口配置、编译系统适配以及常见问题解决方案,帮助开发者高效完成传感器集成与调试工作。

weixin_30374009的博客 416

从FSI到三层堆叠:一文搞懂车载CIS图像传感器技术演进与选型避坑

本文深入解析车载CIS图像传感器从FSI到三层堆叠的技术演进,揭示不同结构在低光性能、HDR表现和温度稳定性上的关键差异。通过实测数据对比,指导智能驾驶系统选型策略,帮助开发者规避成本与性能的常见陷阱,提升车载摄像头在复杂环境下的成像质量。

weixin_30689307的博客 102

MySQL如何选择索引

MySQL中一张表其实是可以支持多个索引的。但是,你写SQL语句的时候,并没有主动指定使用哪个索引。也就是说,使用哪个索引是由MySQL来确定的。我们先建一个简单的表,表里有a、b两个字段,并分别建上索引然后,我们往表t中插入10万行记录,取值按整数递增,即:(1,1,1),(2,2,2),(3,3,3) 直到(100000,100000,100000)。接下来,我们分析一条SQL语句:图1 使用explain命令查看语句执行情况。

世之奇伟、瑰怪,非常之观,常在于险远,而人之所罕至焉,故非有志者不能至也。 1935

步进电机 cia402协议 报文自己的理解 (笔记)

步进电机 cia402协议 报文自己的理解 (笔记)

she666666的博客 3813

mysql-如何选择索引

mysql-如何选择索引

lin000_0的博客 807

成功解决AttributeError: ‘ImageDraw‘ object has no attribute ‘textsize‘

​ 成功解决AttributeError: 'ImageDraw' object has no attribute 'textsize' 目录 解决问题 解决思路 解决方法 解决问题 AttributeError: 'ImageDraw' object has no attribute 'textsize' 解决思路 属性错误:'ImageDraw'对象没有属性'textsize' 解决方法 最新的Pillow 10.0.0 版本已经删除了这个函数,导致两个库(Pillow 、wordc

头部AI社区如有邀博主AI主题演讲请私信—心比天高,仗剑走天涯,保持热爱,奔赴向梦想!低调,专注,谦虚,自律,反思,成长,还算比较正能量的博主,公益免费传播…内心特别想在AI界做出一些可以推进历史进程影响力的技术(兴趣使然,有点小情怀,也有点使命感呀 4782

VSCode + QMT 量化交易完整解决方案!

🏆本文收录于 《全栈 Bug 调优(实战版)》 专栏。专栏聚焦真实项目中的各类疑难 Bug,从成因剖析 → 排查路径 → 解决方案 → 预防优化全链路拆解,形成一套可复用、可沉淀的实战知识体系。无论你是初入职场的开发者,还是负责复杂项目的资深工程师,都可以在这里构建一套属于自己的「问题诊断与性能调优」方法论,助你稳步进阶、放大技术价值 。

**My Coding Family** 1328

mysql索引选择不对_mysql为什么会选错索引

CREATE TABLE `t` (`id` int(11) NOT NULL,`a` int(11) DEFAULT NULL,`b` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `a` (`a`),KEY `b` (`b`)) ENGINE=InnoDB;用存储过程插入100000条数据delimiter ;;create procedure ida...

weixin_42322467的博客 380

最适合入门的100个深度学习项目

本专栏整理了《PyTorch深度学习项目实战100例》,内包含了各种不同的深度学习项目,包含项目原理以及源码,每一个项目实例都附带有完整的代码+数据集。

优快云 精品推荐 12万+

mysql为什么会选错索引,以及优化器是如何选择索引的

采样统计的时候,InnoDB 默认会选择 N 个数据页,统计这些页面上的不同值,得到一个平均值,然后乘以这个索引的页面数,就得到了这个索引的基数。在 索引建立之后,一条语句可能会命中多个索引,这时,索引的选择,就会交由 优化器 来选择合适的索引。- 因为把整张表取出来一行行统计,虽然可以得到精确的结果,但是代价太高了,所以只能选择“采样统计”。显然,一个索引上不同的值越多,这个索引的区分度就越好。优化器选择索引的目的,是找到一个最优的执行方案,并用最小的代价去执行语句。为什么需要使用 采样统计?

weixin_43831204的博客 795

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

mysql索引选择不对_10 | MySQL为什么有时候会选错索引?

https://time.geekbang.org/column/article/71173可能会出现一种情况,一条本来可以执行的很快的语句,却由于MySQL选错了索引,而导致执行速度变的很慢。先建一个表:CREATE TABLE `t` (`id` INT(11) NOT NULL,`a` INT(11) DEFAULT NULL,`b` INT(11) DEFAULT NULL,PRIMARY...

weixin_28875235的博客 223

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

MySQL 优化器 索引选择_10 | MySQL为什么有时候会选错索引?

前面我们介绍过索引,你已经知道了在MySQL中一张表其实是可以支持多个索引的。但是,你写SQL语句的时候,并没有主动指定使用哪个索引。也就是说,使用哪个索引是由MySQL来确定的。不知道你有没有碰到过这种情况,一条本来可以执行得很快的语句,却由于MySQL选错了索引,而导致执行速度变得很慢?我们一起来看一个例子吧。我们先建一个简单的表,表里有a、b两个字段,并分别建上索引:CREATE TABLE...

weixin_39787345的博客 156

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

mysql索引自动选择_MySQL 笔记整理(10) --MySQL为什么有时会选错索引?

笔记记录自林晓斌(丁奇)老师的《MySQL实战45讲》(本篇内图片均来自丁奇老师的讲解,如有侵权,请联系我删除)10) --MySQL为什么有时会选错索引?MySQL中的一张表上可以支持多个索引的,但是,往往你写SQL语句的时候不会去主动指定使用哪个索引。也就是说,使用哪个索引是由MySQL来确定的。而MySQL有时会选择不恰当的索引,我们举一个例子来说明这种情况。CREATE TABLE`t` ...

weixin_39969340的博客 285

MySQL实战45讲——10|MySQL为什么有时候会选错索引?

MySQL实战45讲——10|MySQL为什么有时候会选错索引?

qq_51931826的博客 468

MySQL为什么有时候会选错索引?

前面我们介绍过索引,你已经知道了在 MySQL 中一张表其实是可以支持多个索引的。但是,你写 SQL 语句的时候,并没有主动指定使用哪个索引。也就是说,使用哪个索引是由MySQL 来确定的。 不知道你有没有碰到过这种情况,一条本来可以执行得很快的语句,却由于 MySQL 选错了索引,而导致执行速度变得很慢? 我们一起来看一个例子吧。 我们先建一个简单的表,表里有 a、b 两个字段,并分别建上索引: CREATE TABLE `t` ( `id` int(11) NOT NULL, `a` int(11)

tom的博客 240

MySQL 为什么有时候会选错索引?

优化器不仅会估算扫描行数,还会考虑普通索引还要进行回表操作,主键索引不需要回表,有些时候尽管主键索引的估算扫描行数多于普通索引,但是普通索引需要回表,所以优化器综合考虑用的还是主键索引。

技术分享,读书笔记,面试宝典,算法积累,应有尽有~ 379

mysql选错索引怎么解决_mysql为什么会选错索引

CREATE TABLE `t` (`id` int(11) NOT NULL,`a` int(11) DEFAULT NULL,`b` int(11) DEFAULT NULL,PRIMARY KEY (`id`),KEY `a` (`a`),KEY `b` (`b`)) ENGINE=InnoDB;用存储过程插入100000条数据delimiter ;;create procedure ida...

weixin_33699970的博客 254

10 | MySQL 为什么有时候会选错索引?

文章目录10 | MySQL 为什么有时候会选错索引?优化器的逻辑索引选择异常和处理小结上期问题时间 10 | MySQL 为什么有时候会选错索引? 在 MySQL 中一张表其实是可以支持多个索引的。但是,你写 SQL 语句的时候,并没有主动指定使用哪个索引。也就是说,使用哪个索引是由 MySQL 来确定的。 不知道你有没有碰到过这种情况,一条本来可以执行得很快的语句,却由于 MySQL 选错了索引,而导致执行速度变得很慢? 我们先建一个简单的表,表里有 a 、 b 两个字段,并分别建上索引: CREATE

sdaujsj1的博客 246

mysql有时候为什么会选错索引

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_34419326的博客 226

Mysql为什么会选错索引?

前面我们介绍过索引,你已经知道了在 MySQL 中一张表其实是可以支持多个索引的。但是,你写 SQL 语句的时候,并没有主动指定使用哪个索引。也就是说,使用哪个索引是由 MySQL 来确定的。不知道你有没有碰到过这种情况,一条本来可以执行得很快的语句,却由于 MySQL 选错了索引,而导致执行速度变得很慢?我们一起来看一个例子吧。然后,我们往表 t 中插入 10 万行记录,取值按整数递增,即:(1,1,1),(2,2,2),(3,3,3) 直到 (100000,100000,100000)。

yonggeit的博客 3955
上一篇: innodb存储引擎之:索引的数据结构(B+TREE)
下一篇: 更详细的执行计划 optimizer_trace
三易的博客
博客等级 码龄15年 42粉丝 89原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值