相信很多人在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是否会用到索引并提高查询效率的探讨的更多相关文章

  1. MySQL深入理解

    [存储引擎] InnoDB表引擎 默认事务型引擎,最重要最广泛的存储引擎,性能非常优秀. 数据存储在共享表空间,可以通过配置分开. 对主键查询的性能高于其他类型的存储引擎. 内部做了很多优化,从磁盘读 ...

  2. 第四课(1)——MySQL体系结构

    学习目标 一.MySQL体系结构 二.MySQL内存结构 三.MySQL文件结构 四.Innodb体系结构 MySQL体系结构 一.MySQL体系结构图 1.Mysql是由SQL接口,解析器,优化器, ...

  3. MySQL面试宝典

    ==============================================# 参数==============================================auto ...

  4. Java面试中常问的数据库方面问题

    MySQL 为什么用自增列作为主键 如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引.如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作 ...

  5. MySQL 必会知识

    一.为什么用自增列作为主键 1.如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引. 如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作为 ...

  6. mysql 常见面试题

    附录: https://mp.weixin.qq.com/s/pC0_Y7M7BkoUmlRwneZZdA 一.为什么用自增列作为主键 1.如果我们定义了主键(PRIMARY KEY),那么InnoD ...

  7. 24个MySQL面试题

    一.为什么用自增列作为主键? 1.如果我们定义了主键(PRIMARY KEY),那么InnoDB会选择主键作为聚集索引. 如果没有显式定义主键,则InnoDB会选择第一个不包含有NULL值的唯一索引作 ...

  8. MySQL数据库索引:索引介绍和使用原则

    本篇目录: 一.数据页与索引页 二.聚簇索引与非聚簇索引 三.唯一索引 四.索引的创建 五.索引的使用规则 六.数据库索引失效情况 本篇正文: 一.数据页与索引页 数据库的表存储分为数据页存储和索引页 ...

  9. MySQL 面试题 24 问

    MySQL 是数据库中的主流中的主流,小中性公司基本都以它为主,而作为后端开发和数据库工程师来说,MySQL 是面试必须要过的一关.以下是小编整理网络的 MySQL 面试高频题,希望对大家有所帮助. ...

随机推荐

  1. win8、win10出现已禁用IEM时的处理办法

    计算机管理--任务计划程序--任务计划程序库--Microsoft--Windows--TextServicesFramework--MsCtfMonitor--运行即可

  2. Android中使用异步线程更新UI视图的几种方法

    在Android中子线程是不能更新ui的. 所以我们要通过其他方式来动态改变ui视图, 1.runOnUiThreadactivity提供的一个轻量级更新ui的方法,在Fragment需要使用的时候要 ...

  3. Android 显示html标签或者带图片

    Android中显示html文件要用Html.fromHtml(...)处理过的返回值,返回值可以成为setText()的参数. 只显示带文本的html可以用下面的方法处理html文件. public ...

  4. 在Qt中使用Font Awesome图标

    官网: http://fontawesome.io/中文网: http://www.fontawesome.com.cn/GitHub: https://github.com/FortAwesome/ ...

  5. 把KB转化为KB及以上单位

    /** * 把KB转化为KB及以上单位 * @param int $kb * @return string $new_val */ function return_over_kb($kb) { $kb ...

  6. Linux虚拟机将ip改为自定义模式网络

    查看当前ip:ifconfig 配置linux的ip地址:vi /etc/sysconfig/network-scripts/ifcfg-ens33 BOOTPROTO="dhcp" ...

  7. switch结构可以更好的解决等值判断问题

    switch 选择结构的语法:switch (表达式){case 常量 1://代码块1:break;case 常量 2://代码块2:break;......default://代码块n:break ...

  8. Python学习---抽屉框架分析[ORM操作]180314

    Django ORM操作     1. 字段操作         class User(model.Model);             u=字段        用处:            1 . ...

  9. LeetCode算法题 菜鸟总结

    近期准备抽出一点时间,刷一些题防止手生,毕竟codemonkey,吃饭的手艺不能忘. ······································· 基本的题目都是基于java语言解答 ...

  10. [T-ARA][SEXY LOVE]

    歌词来源:http://music.163.com/#/song?id=22704402 作曲 : 新沙洞老虎/崔圭成 [作曲 : 新沙洞老虎/崔圭成] [作曲 : 新沙洞老虎/崔圭成] 作词 : 新 ...