Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >这种sql写法会导致索引失效?

这种sql写法会导致索引失效?

作者头像
谭小谭
发布于 2019-07-10 09:45:32
发布于 2019-07-10 09:45:32
69800
代码可运行
举报
文章被收录于专栏:谭小谭谭小谭
运行总次数:0
代码可运行

网上经常能看到一些文章总结在 mysql 中不能命中索引的各种情况,其中有一种说法就是指使用了 or 的语句都不能命中索引。

这种说法其实是不够正确的,正确的结论应该是,从 mysql5.0 后,如果在 or 连接的字段上都有独立的索引的话,是可以命中索引的,这里就是用到了 index_merge 特性。

在 mysql5.0 版本以前一条 sql 只能选择使用一个索引,而且如果 sql 中使用了 or 关键字,那么已有的索引就会失效,会走全表扫描。因为无论走哪个索引,mysql 都不能一次性查找出符合条件的数据,所以只能放弃索引。

mysql 也是一直在不断升级更新,所以在 mysql5.0 版本后,增加了 index_merge 索引合并这个特性,也因此支持了一条 sql 使用多个索引。

index_merge 核心思想就是先分别使用单个索引查出满足要求的数据,然后再将这些数据合并到一起返回。

我们可以看一个的例子。

这里依然沿用我们前面文章中创建的表和测试数据,表中插入了 10 w 条测试数据,表结构如下。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
CREATE TABLE `t` (
  `id` int(11) NOT NULL,
  `a` int(11) DEFAULT NULL,
  `b` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

我们先来给 a 字段添加一个索引,然后执行一条带 or 的查询语句看看。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> alter table t add index a_index(a);
Query OK, 0 rows affected (0.17 sec)
Records: 0  Duplicates: 0  Warnings: 0
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> explain select a from t where a=100 or b=6000;
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | t     | ALL  | a_index       | NULL | NULL    | NULL | 100332 | Using where |
+----+-------------+-------+------+---------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

因为字段 b 上没有索引,mysql 认为走全表扫描代价更低一些,因为可以免去回表过程。

那么我们给 b 字段也加上索引试试,然后再执行刚刚那条 sql 。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> alter table t add index b_index(b);
Query OK, 0 rows affected (0.17 sec)
Records: 0  Duplicates: 0  Warnings: 0
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> explain select a from t where a=100 or b=6000;
+----+-------------+-------+-------------+-----------------+-----------------+---------+------+------+-------------------------------------------+
| id | select_type | table | type        | possible_keys   | key             | key_len | ref  | rows | Extra                                     |
+----+-------------+-------+-------------+-----------------+-----------------+---------+------+------+-------------------------------------------+
|  1 | SIMPLE      | t     | index_merge | a_index,b_index | a_index,b_index | 5,5     | NULL |    2 | Using union(a_index,b_index); Using where |
+----+-------------+-------+-------------+-----------------+-----------------+---------+------+------+-------------------------------------------+
1 row in set (0.00 sec)

这回可以看到 mysql 同时使用了 a、b 两个索引,并且看到 type 字段的值为 index_merge。

接下来再来看另一条 sql,看看结果又是怎样的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
mysql> explain select a from t where a>100 or b>6000;
+----+-------------+-------+------+-----------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys   | key  | key_len | ref  | rows   | Extra       |
+----+-------------+-------+------+-----------------+------+---------+------+--------+-------------+
|  1 | SIMPLE      | t     | ALL  | a_index,b_index | NULL | NULL    | NULL | 100332 | Using where |
+----+-------------+-------+------+-----------------+------+---------+------+--------+-------------+
1 row in set (0.00 sec)

这条 sql 仅仅是把等号改成了大于号,也就是说返回的结果集是一个区间集,mysql 在这里又放弃了索引,走的全表扫描,不过有看文章说在 mysql5.7 版本后优化了这个问题,即在区间查询中也支持使用 index_merge,我的版本是 5.6 ,暂未验证这个优化,有兴趣的可以去验证下。

其实在 mysql 中很多东西都是不绝对的,对于同一条 sql 不同 mysql 版本的内部处理方式有可能是不太一样的,同时也可以看到 mysql 一直在不断优化升级,一些老旧的知识点很容易就会不再适用了。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-07-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 谭小谭 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
第 48 期:EXPLAIN TYPE 列的 JOIN 常见场景详解(下)
对于关系型数据库来说,表的设计 以及 SQL 的写法 尤为重要,占据性能的 90% 都不为过,所以这次专门针对这两大类知识领域,为您抽丝剥茧详细分析。
爱可生开源社区
2025/01/07
600
第 48 期:EXPLAIN TYPE 列的 JOIN 常见场景详解(下)
MySQL中explain的结果​字段介绍
昨天说完了执行计划的前四个字段,今天说说后面几个字段吧。我们看看explain的基本语法和输出内容:
AsiaYe
2019/11/06
8.6K0
MySQL8索引篇:性能提升了100%!!
今天我们一起来聊聊MySQL 8.x版本中新增的三大索引。MySQL 8.x中新增了三种索引方式,这三种索引方式直接让MySQL原地起飞了,如下所示。
冰河
2022/06/15
2.8K0
如何分析一条sql的性能
网上其实已经有非常多的文章都很详细的介绍了 explain 的使用,这篇文章将实例和原理结合起来,尽量让你有更好的理解,相信我,认真看完你应该会有特别的收获。
谭小谭
2019/06/05
7970
你知道MySQL 8.0中的索引有哪些新特性吗?看这一篇就够了!!!
在之前MySQL的版本中,只能通过显式的方式删除索引,如果删除后发现索引删错了,又只能通过创建索引的方式将删除的索引添加回来,如果数据库中的数据量非常大,或者表比较大,这种操作的成本非常高。在MySQL 8.0中,只需要将这个索引先设置为隐藏索引,使查询优化器不再使用这个索引,但是,此时这个索引还是需要MySQL后台进行维护,当确认将这个索引设置为隐藏索引系统不会受到影响时,再将索引彻底删除。这就是软删除功能。
冰河
2020/10/29
1.2K0
你知道MySQL 8.0中的索引有哪些新特性吗?看这一篇就够了!!!
MySQL Explain 使用分析
MySQL 提供了一个 EXPLAIN 命令, 它可以对 SELECT 语句进行分析, 并输出 SELECT 执行的详细信息, 以供开发人员针对性优化.
喝茶去
2019/12/26
3430
技术分享 | 用好 MySQL 的 MRR 优化器
MySQL DBA,擅长 python 和 SQL,目前维护着 github 的两个开源项目:mysqltools 、dbmc 以及独立博客:https://www.sqlpy.com。
爱可生开源社区
2020/06/19
7170
第 53 期:EXPLAIN 中最直观的 rows
MySQL 和大多数关系型数据库一样,SQL 语句执行计划的输出栏都有一行 rows,代表优化器执行这条 SQL 所需算子扫描的记录数,是优化器根据表和索引的统计信息数据评估出来的结果。
爱可生开源社区
2025/03/21
701
第 53 期:EXPLAIN 中最直观的 rows
不会看 Explain执行计划,劝你简历别写熟悉 SQL优化
昨天中午在食堂,和部门的技术大牛们坐在一桌吃饭,作为一个卑微技术渣仔默默的吃着饭,听大佬们高谈阔论,研究各种高端技术,我TM也想说话可实在插不上嘴。
程序员小富
2020/05/20
8510
不会看 Explain执行计划,劝你简历别写熟悉 SQL优化
第22期:索引设计(组合索引适用场景)
建立在多个列上的索引即组合索引(联合索引),适用在多个列必须一起使用或者是从左到右方向部分连续列一起使用的业务场景。
爱可生开源社区
2021/03/16
3250
第22期:索引设计(组合索引适用场景)
MySQL之索引
#alter添加语法:alter table 表名 add primary key(列名)
老油条IT记
2020/03/22
6840
【MySQL】MySQL中SQL语句的索引分析
了解过 索引 的概念以及 B+树 的概念之后,我们就来看看怎么分析一条查询语句的索引使用情况。相信不少同学应该都使用过 EXPLAIN 来分析 SQL 语句,但是具体到 EXPLAIN 中每个字段的作用,可能有不少同学还是会有点晕的。因此,我们也是以总结为主,来简单了解一下 EXPLAIN 的具体使用。
硬核项目经理
2024/04/12
2560
【MySQL】MySQL中SQL语句的索引分析
第 51 期:根据 EXPLAIN EXTRA 栏提示进行优化(三)
爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。----
爱可生开源社区
2025/02/25
750
第 51 期:根据 EXPLAIN EXTRA 栏提示进行优化(三)
mysql执行计划看是否最优
介绍   本篇主要通过汇总网上的大牛的知识,简单介绍一下如何使用mysql的执行计划,并根据执行计划判断如何优化和是否索引最优。   执行计划可显示估计查询语句执行计划,从中可以分析查询的执行情况是否最优,有助于对不使用索引的语句进行优化。EXPLAIN对每个查询返回一行信息,列出了有序的表格,MySQL处理语句的时候读取他们。MySQL解决所有的连接使用嵌套连接方法。这意味读取第一张一行,然后匹配第二张表的所有行,第三张表甚至更多表。当所有的表在处理时,MySQL会输出已经查询出来的列,并且回溯到表继续
用户1217611
2018/03/19
2.1K0
Mysql高级4-索引的使用规则
  如果索引了多列(联合索引),要遵守最左前缀法则。最左前缀法则指的是查询从索引的最左列开始,并且不跳过索引中的列,如果跳跃某一列,索引将部分失效(后面的字段索引失效)
Se7eN_HOU
2023/07/31
4120
Mysql基础篇--面试如何定位低效率sql语句
当面对一个sql性能问题,我们应该从何处入手使得尽快定位问题sql,我们从基础的命令开始
小土豆Yuki
2020/06/15
1.1K0
第23期:索引设计(组合索引不适用场景改造)
上篇文章已经详细介绍 MySQL 组合索引的概念以及其适用场景,这篇主要介绍 MySQL 组合索引的不适用场景以及改造方案。
爱可生开源社区
2021/03/16
2670
第23期:索引设计(组合索引不适用场景改造)
第19期:索引设计(哈希索引数据分布与使用场景)
哈希索引显式应用主要存在于内存表,也就是 Memory 引擎,或者是 MySQL 8.0 的 Temptable 引擎。本篇的内容上都是基于内存表,MySQL 内存表的大小由参数 max_heap_table_size 来控制,其中包含了表数据,索引数据等。
爱可生开源社区
2021/01/13
3610
TYPE(3)—mysql执行计划(四十九)
Union:union和union all都叫几个select,除了最左边的是primary,其他都是union。
用户9919783
2022/07/26
3470
mysql explain type连接类型示例
对于MySQL执行计划的获取,我们可以通过explain方式来查看,explain方式看似简单,实际上包含的内容很多,尤其是输出结果中的type类型列。理解这些不同的类型,对于我们SQL优化举足轻重,本文仅描述explian输出结果中的type列,同时给出其演示。 有关explian输出的全描述,可以参考:MySQL EXPLAIN SQL 输出信息描述 一、EXPLAIN 语句中type列的值 type: 连接类型 system 表只有一行 const
Leshami
2018/08/13
1.6K0
相关推荐
第 48 期:EXPLAIN TYPE 列的 JOIN 常见场景详解(下)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验