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 面试高频题,希望对大家有所帮助. ...
随机推荐
- QT5.9 新特性与版本回顾
原文链接: http://blog.qt.io/blog/2017/05/31/qt-5-9-released 翻译内容如下,采用的是第三方某在线翻译软件,所以有些地方不是太精确,纵然大吉做了一定的调 ...
- 关于 Blog 修改
关于 Blog 修改 本 Blog 使用的是 WordPress,每次升级 WordPress 都需要修改文件,以修正一些问题,因此做个总记录,便于自己修改. 解决 WordPress 无法打开中文链 ...
- Oracle 截取指定长度的字符
去掉回车,换行符号,截取指定长度的字符 具体代码示例: --Function --去掉前后空格,截取字符,字符长度为P_Length create or replace function get_St ...
- 应用程序 调用 webservice
首先用VS创建一个WebService服务工程,并且完成基本功能,本人完成的是html转pdf功能. 然后,新建一个Windows应用程序. 添加WebService到Windows项目中,如图 然后 ...
- Linux修改Oracle用戶
Linux下SSH登陆后: su - Oracle; sqlplus /nolog; conn system/密码; 或者 connect/as sysdba; alter user 用户名 iden ...
- GitHub和SVN的区别
今天了解一下svn和github的区别. 一.版本控制 版本控制是指对软件开发过程中各种程序代码.配置文件及说明文档等文件变更的管理,是软件配置管理的核心思想之一.版本控制最主要的功能就是追踪文件的变 ...
- 通信与实际用例应用(消息队列和进程撰写的ATM机与消息队列的五子棋对站)
int semget(key_t key, int nsems, int semflg); 功能:创建信号量或获取信号量 nsems:信号量的数量 semflg: IPC_CREAT|IPC_EXEC ...
- [翻译] TLTagsControl
TLTagsControl https://github.com/ali312/TLTagsControl#tltagscontrol A nice and simple tags input con ...
- xise官方网站|XISE官网|xise最新版下载|超级XISE WBMS管理V12.0版本官方网站|
诠释: 1. 破解VIP登陆限制 2.去后门 (自查) 下载地址 :https://pan.baidu.com/s/1eR2rUOM 查毒地址:http://a.virscan.org/a3983f3 ...
- codeforces 420D Cup Trick
codeforces 420D Cup Trick 题意 题解 官方做法需要用到线段树+平衡树(? 如果数据小的话似乎可以用莫队).然后代码好长好长.我补了一个只要用到树状数组的做法. 代码 #inc ...