结案了!in到底用不用索引,啥时候能用啥时候不能用

首页>焦点 > 正文
2023-06-16 19:22:14

来源:博客园

in/or到底能不能用索引应该是肯定的,但有时生效有时不生效,这个能不能量化计算?这是本文想讨论和解答的问题。

in到底用不用索引感觉像一桩悬疑片!古早时期的面经,统一说不走索引,在一些程序员脑海中从此留下不可磨灭的印记。有些从业时间较长的程序员脑子里的第一反应就是不走索引,上个月我就曾经被同事这样质疑过。


(相关资料图)

但是那是mysql5.5以前的老黄历了,现在都到8.0+了,5.5(甚至更早)以后可以肯定的是它会走索引。但必然走索引吗?不一定。

我搜索引擎上搜索关键词 in/or索引,出来一大片文章,一般都会说,in/or能走索引,但后面跟的条件个数多了就不走索引了。但问题就来了,这个多了到底是多少才算多?对于一个动态查询的SQL,我咋知道到底走不走索引?如何量化计算呢?

这时候就语焉不详或者直接跳过。

大名鼎鼎的《阿里巴巴JAVA开发规范》倒是一刀切。最好不超过1000。

人家这规范只是推荐,也不是强制,是吧,不能吐槽。

而且超过1000就算用上了range级别的查询,那可能也快不到哪里去啊,对于要求快速响应的互联网需求来说这推荐好像没毛病。

但这不是重点,今天的重点在于,我一定要搞清楚,在保证explain的type为range而不是ALL全表扫描的前提下,到底select * from table where id in (1,2,3.....x)这个x能到多少。

问题

首先建一张测试表,来一步复现一下,走与不走索引的情况。

mysql

版本:5.7.19引擎:innodb

创建一个测试表

CREATE TABLE `t_person` (  `id` int(11) NOT NULL,  `name` varchar(10) COLLATE utf8_bin DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

使用SQL

EXPLAIN SELECT id, NAME FROM t_person WHERE id IN (1)

查看执行计划

此时表里无数据,显示的是no matching row in const table.

少量数据

插入一条数据insert t_person (id,name) values(1,"张三")

使用SQL

EXPLAIN SELECT id, NAME FROM t_person WHERE id IN (1)

查看执行计划

使用了索引,还是效率最高的const(system生产环境不可能的吧),此时id in(1)相当于 id = 1

在in里增加点条件。

sql变成EXPLAIN SELECT id, NAME FROM t_person WHERE id IN (1, 2)

查看执行计划

使用了索引,但级别下降到了range,即范围索引。

继续在in里增加条件。

sql变成EXPLAIN SELECT id, NAME FROM t_person WHERE id IN (1, 2,3)

查看执行计划

索引级别变成了ALL,即全表扫描,其实是索引失效了。

再往表里插入两条数据。此时总共3条数据。

insert t_person (id,name) values(2,"李四")insert t_person (id,name) values(3,"王五")

再使用sqlEXPLAIN SELECT id, NAME FROM t_person WHERE id IN (1, 2,3)

查看执行计划

可以看到,随时表数据的增加,同样的sql执行计划从ALL变回了range,索引又生效了。

同样地,再增加一个in条件,EXPLAIN SELECT id, NAME FROM t_person WHERE id IN (1,2,3,4)的执行计划又变回了ALL,这里就不放图了。

多点数据

以上只是小打小闹撒撒水啦,总共几条数据,in的条件都快超过表数据了,执行计算都不用预估就知道全表扫描还好一点啦。

我再往表里插入100万条数据。

我先按照阿里的开发规范推荐的1000这个值作为临界值,先使用900个条件

再使用1100个条件

上图表明,这两种情况都使用到了range范围索引呢。

再加大剂量,直接上10万。

步子迈大了,咔,这下终于全表扫描了。

但是还是没找到临界值。

官网上寻找答案

https://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html

我在这里寻找到了一个参数,描述的倒像是相似的问题。

这个方法说的是当使用in或or查询时,比如where in(1,2,3),执行引擎会先预估表中的数量,表中的数量将决定使用的查询方式,比如,如果表中只有3条数据,那么很明显,这时候直接全表扫描。

而这个预估的方法有2种,一是dive到index中即利用索引完成元组数的估算,简称index dive; 二是使用索引的统计数值,进行估算.

相比这2种方式,在效果上:

  • index dive: 速度慢,但能得到精确的值(MySQL的实现是数索引对应的索引项个数,所以精确)

  • index statistics: 速度快,但得到的值未必精确.

eq_range_index_dive_limit这个参数确实跟今天的主题相关系数不大。很明显,这个值在mysql 5.7是200, 一开始的in后面的条件个数就是900,依然是走了range索引的。

stackoverflow

于是我找到了stackoverflow,在上面把msyqlincount这些关键词搜了一下,没有找到相关的问题。

然后我把问题详细描述了一下,提了一个新的问题,没想到啊,半个小时不到,人家就直接给我点踩,并给出了相似的已解答问题。

尴尬了。我超喜欢stackoverflow,这里的人个个都是人才。

相似的问题在这里。

https://stackoverflow.com/questions/72361880/mysql-in-operator-on-large-number-of-values

这位仁兄也在in的使用中也有很多问号,in的条件卡在14000左右,超过就失去了range索引。

下面高赞答案提到了一个参数,range_optimizer_max_mem_size ,一看就很有搞头啊。

转到mysql官网,凭我的渣渣英语也能看明白,我知道,大概我找到答案了。

https://dev.mysql.com/doc/refman/5.7/en/range-optimization.html#equality-range-optimization

要控制范围优化器可用的内存,使用range_optimizer_max_mem_size系统变量:

  • 值为0表示“没有限制”。

  • 当值大于0时,优化器将跟踪在考虑范围访问方法时所消耗的内存。如果即将超过指定的限制,则放弃范围访问方法,转而考虑其他方法,包括全表扫描。这可能不太理想。如果发生这种情况,会出现以下警告(其中N是当前的range_optimizer_max_mem_size值)。

现在事情就很简单了。

range_optimizer_max_mem_size默认是8M,使用同样的SQL,in后面同样的条件为固定的19900个,在range_optimizer_max_mem_size=8M,range_optimizer_max_mem_size=8情况下分别执行一下看效果。

range_optimizer_max_mem_size=8M时,走range索引。

range_optimizer_max_mem_size=8时,走ALL全表扫描。

破案了!

明明官网上就有答案,我却三过家门而不入。

结论

in两种情况会走全表扫描。

  • in后面条件导致sql大小超过range_optimizer_max_mem_size。
  • in后面条件个数接近或者等于表数量,执行引擎认为此时全表扫描更加合适。

推而广之,or也是一样的道理。其它> >= < <=应该也是同样的道理。因为它们归根结底都是范围查询。

当然,总体来说,in后面条件越少越好,假设一张表有1000万条数据,in后面的条件有10000个,这时候就算走了range索引,估计效率也好不到哪里。

标签:

THE END
免责声明:本文系转载,版权归原作者所有;旨在传递信息,不代表热讯制鞋网的观点和立场。

相关热点

新华社电 上海市文化和旅游局近日发布《上海市密室剧本杀内容备案管理规定(征求意见稿)》,并截至12月8日面向社会公众广泛征求意见。这
2021-11-19 13:46:03
《中国证券报》17日刊发文章《备战2022 基金经理调仓换股布新局》。文章称,距离2021年结束仅剩一个多月,基金业绩分化明显。部分排名靠前
2021-11-19 13:46:03
交通运输部办公厅 中国人民银行办公厅 中国银行保险监督管理委员会办公厅关于进一步做好货车ETC发行服务有关工作的通知各省、自治区、直
2021-11-19 13:45:58
新华社北京11月17日电 题:从10月份市场供需积极变化看中国经济韧性新华社记者魏玉坤、丁乐读懂中国经济,一个直观的视角就是市场供需两端
2021-11-19 13:45:58
全国教育财务工作会议披露的消息称,2020年,中国国家财政性教育经费投入达4 29万亿元,占GDP总量的4 206%,我国国家财政性教育经费支出占G
2021-11-19 13:45:48
如果你也热爱“种草”,前方高能预警!让你心心念念、“浏览”忘返的网络平台,可能早已成为一块块“韭菜地”。近日,据《半月谈》报道,有...
2021-11-19 13:45:48
日前,工业和信息化部印发《“十四五”信息通信行业发展规划》(以下简称《规划》),描绘了未来5年信息通信行业的发展趋势。《规划》指出...
2021-11-19 13:45:40
本报讯(中青报·中青网记者 周围围)2021年快递业务旺季正式拉开帷幕。国家邮政局监测数据显示,仅11月1日当日,全国共揽收快递包裹5 69
2021-11-19 13:45:40
人民网曼谷11月17日电 (记者赵益普)17日上午,中国援柬埔寨第七批200万剂科兴新冠疫苗抵达金边国际机场。当天,柬埔寨政府在机场举行了
2021-11-19 13:45:35
金坛压缩空气储能国家试验示范项目主体工程一角受访者供图依托清华大学非补燃压缩空气储能技术,金坛压缩空气储能项目申请专利百余项,建立
2021-11-19 13:45:35
视觉中国供图42亿立方米据有关部门预计,今年山西煤炭产量有望突破12亿吨,12月份山西外送电能力将超过900万千瓦,今冬明春煤层气产量将达4
2021-11-19 13:44:34
14省份相继发布2021年企业工资指导线——引导企业合理提高职工工资今年以来,天津、新疆、内蒙古、陕西、西藏、山东、江西、山西、福建、四
2021-11-19 13:44:34
中新网客户端北京11月18日电 (记者 谢艺观)“一条路海角天涯,两颗心相依相伴,风吹不走誓言,雨打不湿浪漫,意济苍生苦与痛,情牵天下喜
2021-11-19 13:44:31
近日,交通运输部等三部门发布《关于进一步做好货车ETC发行服务有关工作的通知》。通知提到,对不具备授信条件的用户,商业银行可在依法合
2021-11-19 13:44:31
欧莱雅面膜陷优惠“年度最大”风波 涉及该事件集体投诉超6000人次美妆大牌双十一促销翻车?近日,因预售价格比双十一现货贵出66%,欧莱雅
2021-11-19 13:44:13
43 6%受访者会在工作两三年后考虑跳槽54 3%受访者认为跳槽对个人职业发展有利有弊如今对不少年轻人来说,想对一份工作“从一而终”不太容易
2021-11-19 13:44:13
超八成受访青年表示如有机会愿意开展副业 规划能力最重要64 4%受访青年指出做副业跟风心态最要不得如今,“身兼数职”已成为年轻人当中的
2021-11-19 13:44:01
发展氢能正当其时【科学随笔】氢能是一种二次能源,它通过一定的方法利用其他能源制取,具有清洁无污染、可储存、与多种能源便捷转换等优点
2021-11-19 13:44:01
“千杯不醉”的解酒“神药”能信吗?专家:网红“解酒药” 其实不算药俗话说,“酒逢知己千杯少”,酒一直是国人饭桌上至关重要的存在。尽...
2021-11-19 13:43:57
最新文章

相关推荐