mysql5.7关于使用到OR是否会用到索引并提高查询效率的探讨
相信很多人在mysql中看到了where条件中使用到了or就会以为这样是不会走索引的,通常会使用union all或者in 来进行优化,事实并不是想象的这样具体问题具体分析。
下面我们来看看
首先我们用sysbench生成两个100w行的表
表结构如下
mysql> show create table sbtest1 \G;
*************************** 1. row ***************************
Table: sbtest1
Create Table: CREATE TABLE `sbtest1` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`k` int(11) NOT NULL DEFAULT '',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k_1` (`k`),
KEY `c_1` (`c`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1
1 row in set (0.00 sec) ERROR:
No query specified mysql> show create table sbtest2 \G;
*************************** 1. row ***************************
Table: sbtest2
Create Table: CREATE TABLE `sbtest2` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`k` int(11) NOT NULL DEFAULT '',
`c` char(120) NOT NULL DEFAULT '',
`pad` char(60) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `k_2` (`k`),
KEY `c_2` (`c`)
) ENGINE=InnoDB AUTO_INCREMENT=1000001 DEFAULT CHARSET=latin1
1 row in set (0.00 sec) ERROR:
No query specified
1.首先我们使用同一列带索引字段的进行查询。
mysql> explain select * from sbtest1 where k='' or k='';
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | sbtest1 | NULL | range | k_1 | k_1 | 4 | NULL | 214 | 100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
从执行计划中看出这样是可以使用到索引的,另外我们使用in 或者union all来看。
mysql> explain select pad from sbtest1 where k in ('','');
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| 1 | SIMPLE | sbtest1 | NULL | range | k_1 | k_1 | 4 | NULL | 214 | 100.00 | Using index condition |
+----+-------------+---------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
in的执行计划和or相同。
mysql> explain select pad from sbtest1 where k='' union all select pad from sbtest1 where k='';
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+------+----------+-------+
| 1 | PRIMARY | sbtest1 | NULL | ref | k_1 | k_1 | 4 | const | 113 | 100.00 | NULL |
| 2 | UNION | sbtest1 | NULL | ref | k_1 | k_1 | 4 | const | 101 | 100.00 | NULL |
虽然执行计划不通但union all估计的查询行数和上面相同。
2.我们再来看看不同列带索引字段的进行查询
mysql> explain select pad from sbtest1 where k='' or c='68487932199-96439406143-93774651418-41631865787-96406072701-20604855487-25459966574-28203206787-41238978918-19503783441';
+----+-------------+---------+------------+-------------+---------------+---------+---------+------+------+----------+-----------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------------+---------------+---------+---------+------+------+----------+-----------------------------------+
| 1 | SIMPLE | sbtest1 | NULL | index_merge | k_1,c_1 | k_1,c_1 | 4,120 | NULL | 114 | 100.00 | Using union(k_1,c_1); Using where |
+----+-------------+---------+------------+-------------+---------------+---------+---------+------+------+----------+-----------------------------------
这样的情况也会使用索引
如果or的条件中有个条件不带索引的话,那这条sql就不会使用到索引了,如下。
mysql> explain select pad from sbtest1 where k='' or pad='00592560354-80393027097-78244247549-39135306455-88936868384';
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | sbtest1 | NULL | ALL | k_1 | NULL | NULL | NULL | 986400 | 19.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+------+--------+----------+-------------+
pad列没索引所以整条的sql就不会使用到索引
假设使用union all来改写一样需要全表扫描所以意义也不大,如下
mysql> explain select pad from sbtest1 where k='' union all select pad from sbtest1 where pad='00592560354-80393027097-78244247549-39135306455-88936868384';
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
| 1 | PRIMARY | sbtest1 | NULL | ref | k_1 | k_1 | 4 | const | 113 | 100.00 | NULL |
| 2 | UNION | sbtest1 | NULL | ALL | NULL | NULL | NULL | NULL | 986400 | 10.00 | Using where |
+----+-------------+---------+------------+------+---------------+------+---------+-------+--------+----------+-------------+
3.接下来我们看看多表关联查询
mysql> explain select a.pad,b.pad from sbtest1 a,sbtest2 b where a.id=b.id and (a.c='' or b.c='');
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+--------+----------+-------------+
| 1 | SIMPLE | a | NULL | ALL | PRIMARY,c_1 | NULL | NULL | NULL | 986400 | 100.00 | NULL |
| 1 | SIMPLE | b | NULL | eq_ref | PRIMARY,c_2 | PRIMARY | 4 | test.a.id | 1 | 100.00 | Using where |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+--------+----------+-------------+
2 rows in set, 1 warning (0.00 sec) mysql> explain select a.pad,b.pad from sbtest1 a,sbtest2 b where a.id=b.id and (a.c='' or a.c='');
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-----------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-----------------------+
| 1 | SIMPLE | a | NULL | range | PRIMARY,c_1 | c_1 | 120 | NULL | 2 | 100.00 | Using index condition |
| 1 | SIMPLE | b | NULL | eq_ref | PRIMARY | PRIMARY | 4 | test.a.id | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-----------------------+
2 rows in set, 1 warning (0.00 sec) mysql>
可以看出在多表查询的情况下or条件如果不在同一个表内执行计划表a的查询不走索引。
我们试试看用union all来进行改写
mysql> explain select a.pad,a.c from sbtest1 a,sbtest2 b where a.id=b.id and a.c='' union all select a.pad,a.c from sbtest1 a,sbtest2 b where a.id=b.id and b.c='';
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------------+
| 1 | PRIMARY | a | NULL | ref | PRIMARY,c_1 | c_1 | 120 | const | 1 | 100.00 | NULL |
| 1 | PRIMARY | b | NULL | eq_ref | PRIMARY | PRIMARY | 4 | test.a.id | 1 | 100.00 | Using index |
| 2 | UNION | b | NULL | ref | PRIMARY,c_2 | c_2 | 120 | const | 1 | 100.00 | Using index |
| 2 | UNION | a | NULL | eq_ref | PRIMARY | PRIMARY | 4 | test.b.id | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+---------------+---------+---------+-----------+------+----------+-------------+
在or的条件不在同一个表的情况下 使用union all来改写扫描行数减少且会走索引。
mysql5.7关于使用到OR是否会用到索引并提高查询效率的探讨的更多相关文章
- MySQL深入理解
[存储引擎] InnoDB表引擎 默认事务型引擎,最重要最广泛的存储引擎,性能非常优秀. 数据存储在共享表空间,可以通过配置分开. 对主键查询的性能高于其他类型的存储引擎. 内部做了很多优化,从磁盘读 ...
- 第四课(1)——MySQL体系结构
学习目标 一.MySQL体系结构 二.MySQL内存结构 三.MySQL文件结构 四.Innodb体系结构 MySQL体系结构 一.MySQL体系结构图 1.Mysql是由SQL接口,解析器,优化器, ...
- MySQL面试宝典
==============================================# 参数==============================================auto ...
- Java面试中常问的数据库方面问题
MySQL 为什么用自增列作为主键 如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引.如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作 ...
- MySQL 必会知识
一.为什么用自增列作为主键 1.如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引. 如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为 ...
- mysql 常见面试题
附录: https://mp.weixin.qq.com/s/pC0_Y7M7BkoUmlRwneZZdA 一.为什么用自增列作为主键 1.如果我们定义了主键(PRIMARY KEY),那么InnoD ...
- 24个MySQL面试题
一.为什么用自增列作为主键? 1.如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引. 如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作 ...
- MySQL数据库索引:索引介绍和使用原则
本篇目录: 一.数据页与索引页 二.聚簇索引与非聚簇索引 三.唯一索引 四.索引的创建 五.索引的使用规则 六.数据库索引失效情况 本篇正文: 一.数据页与索引页 数据库的表存储分为数据页存储和索引页 ...
- MySQL 面试题 24 问
MySQL 是数据库中的主流中的主流,小中性公司基本都以它为主,而作为后端开发和数据库工程师来说,MySQL 是面试必须要过的一关.以下是小编整理网络的 MySQL 面试高频题,希望对大家有所帮助. ...
随机推荐
- linux整个日志目录查询记录
在linux下面需要查看整个目录的日志,搜索用户的一个行为.因为不知道具体是那一天,一个个的查询也可以,但是太麻烦.可以用过下面的命令来实现: rep -iRl "关键字" ./ ...
- 启用代理导致 有道云笔记未知错误、网络错误和OneDrive断线
最近有道云笔记和OneDrive时不时的连接不上服务器,不知道什么原因?后来到有道官网上看了下,才发现,和IE浏览器的设置有关系: 我本地因为之前设置了代理,然后自己忘记了,代理的软件没开,导致IE上 ...
- Azure 虚拟机如何配置 AntiMalware
本文仅演示通过 PowerShell 方式安装并配置 AntiMalware 的过程. 经典虚拟机 立即访问http://market.azure.cn 加载 Antimalware ...
- Java笔记-添加自定义公共类库
大型项目,为了方便团队开发,需要建立公共类库,提高类库的重用性和维护性步骤如下: --如果朋友您想转载本文章请注明转载地址"http://www.cnblogs.com/XHJT/p/387 ...
- Python初学者第十九天 函数(3)
19day 函数 1.作用域 Python中,一个函数就是一个作用域.所有的局部变量都是放在当前的作用域里面 代码定义完成后,作用域已经生成,作用域链向上查找 2.匿名函数 当需要暂时性的用到一个函数 ...
- Vscode rg.exe cpu 占用过高
文件-> 首选项 -> 设置 -> 搜索search.followSymlinks 或者 修改settings.json 添加 "search.followSymlinks ...
- 主存储器与CPU的连接
半导体存储器的读写时间一般在十几至几百毫微秒之间,其芯片集成度高,体积小,片内含有译码器和寄存器等电路.常用的半导体存储器芯片有多字一位片和多字多位片,如16M位容量的芯片可以有16M×1位和4M×4 ...
- SuperSocket.ClientEngine介绍
项目地址:https://github.com/kerryjiang/SuperSocket.ClientEngine 其中需要引入的SuperSocket.ProtoBase项目:SuperSock ...
- java String 常用方法集合
String a = "abc";String b = "abc";a==b ;//返回true,因为a,b指向的是同一个地址 String a = new S ...
- 定义路由的state参数
使用$stateProvider.state('stateName', {url: '', params: {}, views: {},...})创建路由,其中部分参数解析: params: 是一个包 ...