首页 > 技术分享 > MySQL
收藏

简述MySQL使用OR连接查询时索引不生效的问题

08/09 16:49
大潇博客 原创文章,转载请标明出处

本文只为印证一句话:MySQL在使用or连接查询时,如果OR两边的条件有一个没有索引时,整条语句都不会使用索引


这里创建一张表,添加400万条数据进行测试

数据过少时MySQL可能不会使用索引,因为它会认为直接查询速度更快,所以为了结果的准确性,这里添加400万条数据


#创建一张表

CREATE TABLE emp

(empno  MEDIUMINT UNSIGNED  NOT NULL  DEFAULT 0, /*编号*/

ename VARCHAR(20) NOT NULL DEFAULT "", /*名字*/

job VARCHAR(9) NOT NULL DEFAULT "",/*工作*/

mgr MEDIUMINT UNSIGNED NOT NULL DEFAULT 0,/*上级编号*/

hiredate DATE NOT NULL,/*入职时间*/

sal DECIMAL(7,2)  NOT NULL,/*薪水*/

comm DECIMAL(7,2) NOT NULL,/*红利*/

deptno MEDIUMINT UNSIGNED NOT NULL DEFAULT 0 /*部门编号*/

)ENGINE=MyISAM DEFAULT CHARSET=utf8 ;


#定义一个新的命令结束符号,原来的命令结束符在构建函数时会被占用

delimiter $$

#删除自定的函数

drop  function rand_string$$


#创建 rand_string(n INT) 函数,该函数接收一个整数,生成一个随机字符串

create function rand_string(n INT) 

returns varchar(255) #该函数会返回一个字符串

begin 

#chars_str定义一个变量 chars_str,类型是 varchar(100),默认值'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';

 declare chars_str varchar(100) default

   'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';

 declare return_str varchar(255) default '';

 declare i int default 0;

 while i < n do 

   set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));

   set i = i + 1;

   end while;

  return return_str;

  end $$


#自定一个函数,生成一个随机的数字

create function rand_num( )

returns int(5)

begin 

 declare i int default 0;

 set i = floor(10+rand()*500);

return i;

  end $$


#创建一个存储过程

#start表示雇员的编号从哪里开始,max_num 表示一共增加多少雇员

create procedure insert_emp(in start int(10),in max_num int(10))

begin

declare i int default 0; 

#set autocommit =0 把autocommit设置成0

 set autocommit = 0;  

 repeat

 set i = i + 1;

 insert into emp values ((start+i) ,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());

  until i = max_num

 end repeat;

   commit;

 end $$


#把命令结束符号换回原来的分号

delimiter ;


#调用刚刚写好的函数, 1800000条记录,从100001号开始

call insert_emp(100001,4000000);


#分别给上表中的ename和deptno字段创建普通索引

create index my_index1 on emp (ename);

create index my_index2 on emp (deptno);


表结构

表结构.png


首先用没有索引的列和有索引的列搭配查询

explain select * from emp where ename = 'MGSrOl' or empno = 369\G

没有使用索引.png

结果告诉我们,查询到其中一个有索引,但是并没有使用


用都有索引的列查询

explain select * from emp where ename = 'MGSrOl' or deptno = 369\G

使用索引.png

这个结果说明,使用OR连接查询时,如果两边的条件都有索引,那么便会使用索引查询,注意这种情况是在存储引擎为MyISAM的情况下,如果存储引擎为InnoDB会是什么样,下面继续验证。


我们把上面创建的emp表删除后重新创建,把末尾的存储引擎改为“ENGINE=InnoDB”,同样插入400万条数据,创建相同的索引,查询结果如下

QQ图片20190820160559.png

结果说明,存储引擎为InnoDB时,使用OR连接查询,两边条件都有索引的情况下,同样可以索引进行查询。


以上两次验证结果说明:

MySQL在使用or连接查询时,如果两or两边的条件都创建了索引,那么查询便会正常使用索引

or两边的条件有一个没有创建索引,整条语句都不会使用索引


打赏

阅读排行

大家都在搜

博客维护不易,感谢你的肯定
扫码打赏,建议金额1-10元
  • 15601023311