MySQL中 IN 到底走不走索引?

server/2025/3/13 15:57:51/

文章目录

  • 前言
  • 数据库表结构
  • 查询sql
  • EXPLAIN介绍
    • EXPLAIN 的输出每列解释
  • 强制走索引
  • 查询时添加条件(复合索引字段)
    • 查询小时
    • 查询分钟
  • 总结


前言

在 MySQL 中,IN 语句是否能够利用索引取决于多个因素,包括但不限于查询的具体形式、表的统计信息、索引的选择度等。以下通过几个案例来帮助理解 IN 语句与索引使用的关系。

数据库表结构

CREATE TABLE `device_record_gongdi` (`id` varchar(32) NOT NULL COMMENT '主键',`device_code` varchar(32) NOT NULL COMMENT '设备code',`device_type` tinyint(1) NOT NULL COMMENT '设备类型(0:微站设备 1:工地扬尘监测)',`time_type` tinyint(1) DEFAULT NULL COMMENT '时间类型(1:一分钟 2:五分钟 3:一小时)',`cn` varchar(4) DEFAULT NULL COMMENT '时间类型编码: 2011 分钟、2051 5分钟、2061 小时',`aqi` int(11) DEFAULT NULL,`level` varchar(50) DEFAULT NULL COMMENT '等级',`pollutions` varchar(255) DEFAULT NULL COMMENT '首要污染物',`zhzs` double(11,3) DEFAULT NULL COMMENT '综合指数',`pm25_avg` double(6,2) unsigned DEFAULT NULL COMMENT 'PM25 指定时间内平均值',`pm10_avg` double(6,2) unsigned DEFAULT NULL COMMENT 'PM10 指定时间内平均值',`so2_avg` double(6,2) unsigned DEFAULT NULL COMMENT 'SO2 指定时间内平均值',`no2_avg` double(6,2) unsigned DEFAULT NULL COMMENT 'NO2 指定时间内平均值',`co_avg` double(6,2) unsigned DEFAULT NULL COMMENT 'CO 指定时间内平均值',`data_time` datetime DEFAULT NULL COMMENT '数据采集时间',`create_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`id`),KEY `gd_data_code_type_time` (`device_code`,`time_type`,`data_time`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=COMPACT COMMENT='工地数据表';

复合索引(联合索引):(device_code,time_type,data_time)

查询sql

使用EXPLAIN查看是否走索引

 EXPLAINSELECT *FROM device_record_gongdiWHERE device_code in ('ZR802241106062','ZR802240801012');

在这里插入图片描述
可以看到没有走索引

EXPLAIN介绍

EXPLAIN 关键字在 MySQL 中是一个非常有用的工具,它可以帮助我们了解 MySQL 如何执行SQL语句。通过使用 EXPLAIN,可以获取 MySQL 执行查询的计划,这包括如何连接表、使用哪些索引、是否进行了文件排序或临时表等详细信息。

EXPLAIN 的输出每列解释

  • id: 表示查询中每个部分的选择标识符。如果查询比较简单,可能只有一个 id。对于复杂查询(如子查询),可能会有多个 id。
  • select_type: 显示对应行是简单还是复杂 SELECT 类型。例如:
    • SIMPLE: 简单查询,不包含子查询或 UNION。
    • PRIMARY: 最外层的查询。
    • SUBQUERY: 子查询中的第一个 SELECT。
    • DERIVED: 派生表(在 FROM 子句中的子查询)。
  • table: 显示该行引用的表名。
  • type: 显示连接类型,从最佳到最差依次为:system, const, eq_ref, ref, range, index, 和 ALL。理想情况下,应尽量避免 ALL 类型,因为它表示全表扫描。
  • possible_keys: 显示 MySQL 在查询过程中可以使用的索引。
  • key: 实际上被 MySQL 选择用来加速查询的索引。如果没有索引被使用,则值为 NULL。
  • key_len: 被选中索引使用的字节数,可以通过这个值来判断是否使用了复合索引的部分字段。
  • ref: 显示与索引比较的列或常量。
  • rows: 估算出找到所需的记录所需要读取的行数,值越小越好
  • Extra: 包含不适合在其他列中显示的额外信息,比如“Using where”, “Using index”, “Using temporary”, “Using filesort”等。

本文主要观察type、key和rows列。

强制走索引

通过使用force index让sql强制走索引

 EXPLAINSELECT *FROM device_record_gongdi force index (gd_data_code_type_time)WHERE device_code in ('ZR802241106062','ZR802240801012');

在这里插入图片描述
可以看到强制走索引后,rows值没有减少,仍然为382258行。
继续向下看

查询时添加条件(复合索引字段)

表中time_type为时间类型,1代表一分钟数据,2代表五分钟数据,3代表一小时数据。
表中创建了复合索引:(device_code,time_type,data_time)

查询小时

 EXPLAINSELECT *FROM device_record_gongdiWHERE device_code in ('ZR802241106062','ZR802240801012')AND time_type = 3;

在这里插入图片描述
可以看到in又走了索引,rows扫描的行数降到了3013

查询分钟

 EXPLAINSELECT *FROM device_record_gongdiWHERE device_code in ('ZR802241106062','ZR802240801012')AND time_type = 1;EXPLAINSELECT *FROM device_record_gongdi force index (gd_data_code_type_time)WHERE device_code in ('ZR802241106062','ZR802240801012')AND time_type = 1;

重点观察rows扫描的行数
在这里插入图片描述
在这里插入图片描述
这里可以发现,在执行sql时,in一般是走索引的。只有当mysql的查询优化器认为走索引时也需要扫描大量的数据时,就会变为全表扫描。(有些地方写的是当走索引查询后,rows值在数据表中的占比不超过 30% 时,大概率会走索引)

分别执行这两条sql
在这里插入图片描述
在这里插入图片描述
从这里也可以看出,当使用索引和不使用索引查询时间相差无几时,in就会不走索引。
注意:查询出的条数不同是因为查询时有数据插入

总结

MySQL 中IN语句不一定会走索引,具体取决于多种因素:

  • IN一般是走索引的。只有当mysql的查询优化器认为走索引时也需要扫描大量的数据时,就会变为全表扫描。
  • 当索引覆盖了IN查询的所有列,即查询所需的数据都能从索引中获取,MySQL 可以使用这个索引来加速查询。
  • IN值列表中的值在索引的前缀位置,MySQL 能够利用索引加速查询。若IN值列表的值不在索引的前缀位置,MySQL 无法借助索引加速查询。
  • 也可以使用EXISTS替代IN,在某些场景下能显著提升查询性能。


http://www.ppmy.cn/server/174656.html

相关文章

使用expect工具实现远程批量修改服务器密码

使用expect工具实现远程批量修改服务器密码 linux服务器安装Expect工具 1、首先查看系统中是否有安装expect。 # whereis expect 2、Expect工具是依赖tcl的,需要先安装tcl #wget https://sourceforge.net/projects/tcl/files/Tcl/8.4.19/tcl8.4.19-src.tar.gz …

LuaJIT 学习(1)—— LuaJIT介绍

文章目录 介绍Extensions Modulesbit.* — Bitwise operationsffi.* — FFI libraryjit.* — JIT compiler controlC API extensionsProfiler Enhanced Standard Library Functionsxpcall(f, err [,args...]) passes arguments例子: xpcall 的使用 load*() handle U…

利用java实现数据分析

1 问题 在日常生活中,对于数据的处理,为了使数据更加直观,我们可以使用柱状图,饼图,折线图等来呈现,同时也可以对数据直接进行一些处理,那怎样用java来处理这类问题呢? 2 方法 代码清…

emacs使用mongosh的方便工具发布

github项目地址: GitHub - csfreebird/emacs_mongosh: 在emacs中使用mongosh快速登录mongodb数据库 * 用途 在emacs中使用mongosh快速登录mongodb数据库, 操作方法: M-x mongosh, 输入数据库名称,然后就可以自动登录,前提是你已经配置好了…

蓝桥杯省赛真题C++B组2024-握手问题

一、题目 【问题描述】 小蓝组织了一场算法交流会议,总共有 50 人参加了本次会议。在会议上,大家进行了握手交流。按照惯例他们每个人都要与除自己以外的其他所有人进行一次握手(且仅有一次)。但有 7 个人,这 7 人彼此之间没有进行握手(但这…

UI自动化测试 —— web端元素获取元素等待实践!

前言 Web UI自动化测试是一种软件测试方法,通过模拟用户行为,自动执行Web界面的各种操作,并验证操作结果是否符合预期,从而提高测试效率和准确性。 目的: 确保Web应用程序的界面在不同环境(如不同浏览器、操作系统)下…

运行一个hadoop程序

在hadoop文件夹下创建wcinput文件夹,在文件夹下创建俩个文本文件 word1.txt,word2.txt文件 分别编辑word1.txt和word2.txt文件内容 hadoop yaen hadoop mapreduce root root 回到hadoop目录下opt/module/hadoop-3.1.3运行命令 hadoop jar share/h…

Linly-Talker:开源数字人框架的技术解析与影响

一、引言:AI 数字人的发展趋势 近年来,数字人(Digital Human) 技术迅速发展,从最早的 2D 虚拟主播,到如今能够进行实时交互的 3D 智能助手,AI 在多模态交互领域的应用愈发广泛。各大互联网公司…