Mysql基于成本选择索引

本篇文章介绍mysql基于成本选择索引的行为,解释为什么有时候明明可以走索引,但mysql却没有走索引的原因

mysql索引失效的场景大致有几种

  1. 不符合最左前缀原则
  2. 在索引列上使用函数或隐式类型转换
  3. 使用like查询,如 %xxx
  4. 回表代价太大
  5. 索引列区分度过低
  6. 数据量少,没有走索引的必要
  7. in中的条件过多

其中前三种失效场景,是因为无法利用索引的有序性。而后面几种场景,则是Mysql从成本上考虑,认为走索引的代价比不走索引的代价高,因此Mysql没有走索引。

同样的,如果我们一个查询,可以利用多个索引,那么mysql最终会走哪个索引呢?这也是基于成本考虑的,哪个索引的成本更低,就使用哪个索引。

我们可以来做个实验。创建一个person表,该表有一个主键索引,一个联合索引,以及一个create_time索引。

CREATE TABLE `person`  (`id` bigint NOT NULL AUTO_INCREMENT,`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL,`score` int NOT NULL,`create_time` timestamp NOT NULL,PRIMARY KEY (`id`) USING BTREE,INDEX `name_score`(`name`, `score`) USING BTREE,INDEX `create_time`(`create_time`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 100000 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;

通过下面的存储过程循环创建 10 万条测试数据。

CREATE DEFINER=`root`@`%` PROCEDURE `insert_person`()
begindeclare c_id integer default 1;while c_id<=100000 doinsert into person values(c_id, concat('name',c_id), c_id+100, date_sub(NOW(), interval c_id second));set c_id=c_id+1;end while;
end

接下来,查看下面语句的执行计划。从执行计划中可以看出该sql可能走name_score和create_time俩个索引。但最终mysql选择的确实全表扫描

EXPLAIN SELECT * FROM person WHERE NAME >'name84059' AND create_time>'2023-09-05 05:00:00'

在这里插入图片描述
我们查询条件的时间从5点修改成22点,在查看执行计划,发现此时走了create_time索引。

EXPLAIN SELECT * FROM person WHERE NAME >'name84059' AND create_time>'2023-09-05 22:00:00'

在这里插入图片描述

同一条sql,不同的查询条件,mysql会根据计算的成本选择走或不走索引。这里的成本主要包括IO成本和CPU成本:

  1. IO 成本,是从磁盘把数据加载到内存的成本。
  2. CPU 成本,是检测数据是否满足条件和排序等 CPU 操作的成本。

我们仔细看上面俩个执行计划的rows列,可以很明显的发现第二个执行计划的rows小得多,也就是说要扫描的行更小,CPU的成本也就会更小,所以mysql选择了走索引。

在Mysql5.6及之后的版本中,我们还可以使用optimizer trace功能查看每个索引、全表扫描具体的成本是多少,从而知道mysql为什么选这个索引,或为什么走全表扫描。

如下代码所示,打开 optimizer_trace 后,再执行 SQL 就可以查询 information_schema.OPTIMIZER_TRACE 表查看执行计划了,最后可以关闭 optimizer_trace 功能:

SET optimizer_trace="enabled=on";
SELECT * FROM person WHERE NAME >'name84059' AND create_time>'2023-09-05 05:00:00';
SELECT * FROM information_schema.OPTIMIZER_TRACE;
SET optimizer_trace="enabled=off";

OPTIMIZER_TRACE部分片段如下:

"analyzing_range_alternatives": {"range_scan_alternatives": [{"index": "name_score","ranges": ["name84059 < name"],"index_dives_for_eq_ranges": true,"rowid_ordered": false,"using_mrr": false,"index_only": false,"rows": 25362,"cost": 27618.4,     #走name_score索引需要花费的成本"chosen": false,	 #没有选择name_score索引"cause": "cost"},{"index": "create_time","ranges": ["0x64f64550 < create_time"],"index_dives_for_eq_ranges": true,"rowid_ordered": false,"using_mrr": false,"index_only": false,"rows": 46320,   	#走create_time索引需要花费的成本"cost": 50440.2,	#没有选择create_time索引"chosen": false,"cause": "cost"}]}
{"considered_execution_plans": [{"plan_prefix": [],"table": "`person`","best_access_path": {"considered_access_paths": [{"rows_to_scan": 92641,"access_type": "scan",		#走全表花费的成本"resulting_rows": 92641,"cost": 9549.9,"chosen": true}]},"condition_filtering_pct": 100,"rows_for_plan": 92641,"cost_for_plan": 9549.9,"chosen": true}]}

从optimizer_trace中我们可以看出,name_score索引、create_time索引、全表扫描的成本分别是27618.4、50440.2、9549.9所以mysql最终选择了全表扫描。

有时候mysql也可能会选错索引,此时我们可以通过FORCE INDEX强制mysql走索引,如:

SELECT * FROM person FORCE INDEX(create_time) WHERE NAME >'name84059' AND create_time>'2023-09-05 05:00:00'

当然,实际上并不建议使用FORCE INDEX,因为mysql的选择往往会更正确

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

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

相关文章

ElMessageBox.prompt 点击确认校验成功后关闭

ElMessageBox.prompt(, 验证取货码, {inputPattern: /^.{1,20}$/,inputErrorMessage: 请输入取货码,inputPlaceholder: 请输入取货码,beforeClose: (action, instance, done) > {if (action confirm) {if (instance.inputValue) {let flag false;if (flag) {done()} else …

pandas(四十三)Pandas实现复杂Excel的转置合并

一、Pandas实现复杂Excel的转置合并 读取并筛选第一张表 df1 pd.read_excel("第一个表.xlsx") df1# 删除无用列 df1 df1[[股票代码, 高数, 实际2]].copy() df1df1.dtypes股票代码 int64 高数 float64 实际2 int64 dtype: object读取并处理第二张表…

jmeter 数据库连接配置 JDBC Connection Configuration

jmeter 从数据库获取变量信息 官方文档参考&#xff1a; [jmeter安装路径]/printable_docs/usermanual/component_reference.html#JDBC_Connection_Configuration 引入数据库连接&#xff1a; 将MySQLjar包存放至jemter指定目录&#xff08;/apache-jmeter-3.3/lib&#xff09…

buuctf web 前5题

目录 一、[极客大挑战 2019]EasySQL 总结&#xff1a; 二、[极客大挑战 2019]Havefun 总结&#xff1a; 三、[HCTF 2018]WarmUp 总论&#xff1a; 四、[ACTF2020 新生赛]Include 总结&#xff1a; 五、[ACTF2020 新生赛]Exec 总结&#xff1a; 一、[极客大挑战 2019]…

有哪些适合初学者的编程语言?

C语言 那为什么我还要教你C语言呢&#xff1f;因为我想要让你成为一个更好、更强大的程序员。如果你要变得更好&#xff0c;C语言是一个极佳的选择&#xff0c;其原因有二。首先&#xff0c;C语言缺乏任何现代的安全功能&#xff0c;这意味着你必须更为警惕&#xff0c;时刻了…

Json“牵手”易贝商品详情数据方法,易贝商品详情API接口,易贝API申请指南

易贝是一个可让全球民众在网上买卖物品的线上拍卖及购物网站&#xff0c;易贝&#xff08;EBAY&#xff09;于1995年9月4日由Pierre Omidyar以Auctionweb的名称创立于加利福尼亚州圣荷塞。人们可以在易贝上通过网络出售商品。2014年2月20日&#xff0c;易贝宣布收购3D虚拟试衣公…

Knowledge Graph Prompting for Multi-Document Question Answering

本文是LLM系列文章&#xff0c;针对《Knowledge Graph Prompting for Multi-Document Question Answering》的翻译。 多文档问答中的知识图谱提示 摘要1 引言2 符号3 知识图谱构建4 LM引导的图形遍历器5 实验6 相关工作7 结论 摘要 大型语言模型的“预训练、提示、预测”范式…

layui 富文本编辑器layedit 以及 图片转base64前端页面显示

js var index layui.layedit.build(noticeInformationContent, {area: [500px, 400px],uploadImage: {url: NI/uploadconimage //接口url, type: POST //默认post},hideTool: [image]});layui.form.verify({content: function (val) {layui.layedit.sync(index);var content …

前端面试的话术集锦第 7 篇:高频考点(浏览器渲染原理 安全防范)

这是记录前端面试的话术集锦第七篇博文——高频考点(浏览器渲染原理 & 安全防范),我会不断更新该博文。❗❗❗ 1. 浏览器渲染原理 注意:该章节都是⼀个⾯试题。 1.1 渲染过程 1.1.1 浏览器接收到HTML⽂件并转换为DOM树 当我们打开⼀个⽹⻚时,浏览器都会去请求对应的…

各种UI库使用总结

各种UI库使用总结 工作了这么年&#xff0c;使用了一些UI库&#xff0c;简单的总结一下&#xff0c;UI库也是五花八门&#xff0c;根据自己的产品&#xff0c;应用场景吧&#xff0c;没有绝对合适的&#xff0c;各有各的应用场景吧&#xff01; QT 这几年前后在一些嵌入式上…

LeetCode 630. Course Schedule III【反悔贪心,堆,排序】中等

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

Progresql数据库安装--安装

--安装progresql数据库 systemctl disable firewalld systemctl status firewalld systemctl stop firewalld --准备工作 yum install epel-release.noarch -y yum install libzstd.x86_64 -y # Install the repository RPM: s sudo yum install -y https://download.postgresq…

SpringMVC的简介及工作流程

一.简介 Spring MVC是一个基于Java的开发框架&#xff0c;用于构建灵活且功能强大的Web应用程序。它是Spring Framework的一部分&#xff0c;提供了一种模型-视图-控制器&#xff08;Model-View-Controller&#xff0c;MVC&#xff09;的设计模式&#xff0c;用于组织和管理Web…

MATLAB中isoutlier函数用法

目录 语法 说明 示例 检测向量中的离群值 使用均值检测方法 使用移窗检测法 检测矩阵中的离群值 可视化离群值阈值 isoutlier函数的功能是查找数据中的离群值 语法 TF isoutlier(A) TF isoutlier(A,method) TF isoutlier(A,"percentiles",threshold) TF…

你们分库分表使用什么中间件,有什么优点和缺点?

分析&回答 根据自己的实际使用来说&#xff1a; cobar 阿里 b2b 团队开发和开源的&#xff0c;属于 proxy 层方案。早些年还可以用&#xff0c;但是最近几年都没更新了&#xff0c;基本没啥人用&#xff0c;差不多算是被抛弃的状态吧。而且不支持读写分离、存储过程、跨…

【React】React学习:从初级到高级(四)

React学习[四] 4 应急方案4.1 使用ref引用值4.1.1 给组件添加ref4.1.2 ref和state的不同之处4.1.3 何时使用ref 4.2 使用ref操作DOM4.2.1 获取指向节点的ref4.2.3 使用 ref 回调管理 ref 列表4.2.4 访问另一个组件的DOM节点4.2.5 用 flushSync 同步更新 state 4.3 使用Effect同…

controller接口上带@PreAuthorize的注解如何访问 (postman请求示例)

1. 访问接口 /*** 查询时段列表*/RateLimiter(time 10,count 10)ApiOperation("查询时段列表")PreAuthorize("ss.hasPermi(ls/sy:time:list)")GetMapping("/list")public TableDataInfo list(LsTime lsTime){startPage();List<LsTime> l…

01 PHP基础知识讲解

一 php基础知识 PHP文件的默认拓展名是“php”。 PHP文件中包含HTML标记、PHP标记、PHP代码以及空格和注释。 PHP标记&#xff1a;开始标记<?php 结束标记 ?> 中间内容是PHP代码。 PHP代码&#xff1a;学习第一个指令 echo 功能是用于输出字符串 。 语句结束符&a…

Kotlin+MVVM 构建todo App 应用

作者&#xff1a;易科 项目介绍 使用KotlinMVVM实现的todo app&#xff0c;功能界面参考微软的Todo软件&#xff08;只实现了核心功能&#xff0c;部分功能未实现&#xff09;。 功能模块介绍 项目模块&#xff1a;添加/删除项目&#xff0c;项目负责管理todo任务任务模块&a…

信息化发展29

虚拟现实概述 建立一个能包容图像、声音、化学气味等多种信息源的信息空间&#xff0c; 将其与视觉、听觉、嗅觉、口令、手势等人类的生活空间交叉融&#xff0c; 虚拟现实的技术应运而生。 1 、虚拟现实技术的主要特征包括沉浸性、交互性、多感知性、构想性&#xff08;也称想…