解决MySQL中IN子查询会导致无法使用索引问题_Mysql_脚本之家


本站和网页 https://www.jb51.net/article/117412.htm 的作者无关,不对其内容负责。快照谨为网络故障时之索引,不代表被搜索网站的即时页面。

解决MySQL中IN子查询会导致无法使用索引问题_Mysql_脚本之家
脚本之家
服务器常用软件
手机版
投稿中心
关注微信
快捷导航
软件下载
android
MAC
驱动下载
字体下载
DLL
源码下载
PHP
ASP.NET
ASP
JSP
软件编程
C#
JAVA
C 语言
Delphi
Android
网络编程
PHP
ASP.NET
ASP
JavaScript
在线工具
CSS格式化
JS格式化
Html转化为Js
数据库
MYSQL
MSSQL
oracle
DB2
MARIADB
CMS
PHPCMS
DEDECMS
帝国CMS
WordPress
常用工具
PHP开发工具
python
Photoshop
必备软件
网站首页
网页制作
网络编程
脚本专栏
脚本下载
数据库
服务器
电子书籍
操作系统
网站运营
平面设计
其它
媒体动画
电脑基础
硬件教程
网络安全
MsSql
Mysql
mariadb
oracle
DB2
mssql2008
mssql2005
SQLite
PostgreSQL
MongoDB
Redis
Access
数据库文摘
数据库其它
您的位置:首页 → 数据库 → Mysql → MySQL中IN子查询会导致无法使用索引
解决MySQL中IN子查询会导致无法使用索引问题
更新时间:2017年06月29日 08:38:42 作者:MSSQL123
这篇文章主要介绍了MySQL中IN子查询会导致无法使用索引问题,文章给大家介绍了两种子查询的写法,需要的朋友可以参考下
今天看到一篇关于MySQL的IN子查询优化的案例,
一开始感觉有点半信半疑(如果是换做在SQL Server中,这种情况是绝对不可能的,后面会做一个简单的测试。)
随后动手按照他说的做了一个表来测试验证,发现MySQL的IN子查询做的不好,确实会导致无法使用索引的情况(IN子查询无法使用所以,场景是MySQL,截止的版本是5.7.18)
MySQL的测试环境
测试表如下
create table test_table2
id int auto_increment primary key,
pay_id int,
pay_time datetime,
other_col varchar(100)
建一个存储过程插入测试数据,测试数据的特点是pay_id可重复,这里在存储过程处理成,循环插入300W条数据的过程中,每隔100条数据插入一条重复的pay_id,时间字段在一定范围内随机
CREATE DEFINER=`root`@`%` PROCEDURE `test_insert`(IN `loopcount` INT)
LANGUAGE SQL
NOT DETERMINISTIC
CONTAINS SQL
SQL SECURITY DEFINER
COMMENT ''
BEGIN
declare cnt int;
set cnt = 0;
while cnt< loopcount do
insert into test_table2 (pay_id,pay_time,other_col) values (cnt,date_add(now(), interval floor(300*rand()) day),uuid());
if (cnt mod 100 = 0) then
insert into test_table2 (pay_id,pay_time,other_col) values (cnt,date_add(now(), interval floor(300*rand()) day),uuid());
end if;
set cnt = cnt + 1;
end while;
END
  执行 call test_insert(3000000); 插入303000行数据
两种子查询的写法
查询大概的意思是查询某个时间段之内的业务Id大于1的数据,于是就出现两种写法。
第一种写法如下:IN子查询中是某段时间内业务统计大于1的业务Id,外层按照IN子查询的结果进行查询,业务Id的列pay_id上有索引,逻辑也比较简单,这种写法,在数据量大的时候确实效率比较低,用不到索引
select * from test_table2 force index(idx_pay_id)
where pay_id in (
  select pay_id from test_table2
  where pay_time>="2016-06-01 00:00:00"
    AND pay_time<="2017-07-03 12:59:59"
  group by pay_id
  having count(pay_id) > 1
);
执行结果:2.23秒
第二种写法,与子查询进行join关联,这种写法相当于上面的IN子查询写法,下面测试发现,效率确实有不少的提高
select tpp1.* from test_table2 tpp1,
select pay_id
from test_table2
WHERE pay_time>="2016-07-01 00:00:00"
AND pay_time<="2017-07-03 12:59:59"
group by pay_id
having count(pay_id) > 1
) tpp2
where tpp1.pay_id=tpp2.pay_id
  执行结果:0.48秒
  In子查询的执行计划,发现外层查询是一个全表扫描的方式,没有用到pay_id上的索引
  join自查的执行计划,外层(tpp1别名的查询)是用到pay_id上的索引的。
  后面想对第一种查询方式使用强制索引,虽然是不报错的,但是发现根本没用
  如果子查询是直接的值,则是可以正常使用索引的。
  可见MySQL对IN子查询的支持,做的确实不怎么样。
  另外:加一个使用临时表的情况,虽然比不少join方式查询的,但是也比直接使用IN子查询效率要高,这种情况下,也是可以使用到索引的,不过这种简单的情况,是没有必要使用临时表的。
  下面是类似案例在sqlserver 2014中的测试,几万完全一样的测试表结构和数量,可见这种情况下,两种写法,在SQL Server中可以认为是完全一样的(执行计划+效率),这一点SQL Server要比MySQL强不少
  下面是sqlserver中的测试环境脚本。
create table test_table2
id int identity(1,1) primary key,
pay_id int,
pay_time datetime,
other_col varchar(100)
begin tran
declare @i int = 0
while @i<300000
begin
insert into test_table2 values (@i,getdate()-rand()*300,newid());
if(@i%1000=0)
begin
insert into test_table2 values (@i,getdate()-rand()*300,newid());
end
set @i = @i + 1
end
COMMIT
GO
create index idx_pay_id on test_table2(pay_id);
create index idx_time on test_table2(pay_time);
GO
select * from test_table2
where pay_id in (
select pay_id from test_table2
where pay_time>='2017-01-21 00:00:00'
AND pay_time<='2017-07-03 12:59:59'
group by pay_id
having count(pay_id) > 1
);
select tpp1.* from test_table2 tpp1,
select pay_id
from test_table2
WHERE pay_time>='2017-01-21 00:00:00'
AND pay_time<='2017-07-30 12:59:59'
group by pay_id having
count(pay_id) > 1
) tpp2
where tpp1.pay_id=tpp2.pay_id
总结:在MySQL数据中,截止5.7.18版本,对IN子查询,仍要慎用
您可能感兴趣的文章:MySQL里面的子查询实例详解MySQL子查询(嵌套查询)、联结表、组合查询详细讲述MySQL中的子查询操作mysql in语句子查询效率慢的优化技巧示例MySQL优化之使用连接(join)代替子查询mysql实现多表关联统计(子查询统计)示例MYSQL子查询和嵌套查询优化实例解析Mysql子查询IN中使用LIMIT应用示例MySQL中表子查询与关联子查询的基础学习教程MySQL子查询详细教程
mysql
子查询
索引
in
相关文章
完美解决phpstudy安装后mysql无法启动(无需删除原数据库,无需更改任何配置,无需更改端口)直接共存这篇文章主要介绍了完美解决phpstudy安装后mysql无法启动(无需删除原数据库,无需更改任何配置,无需更改端口)直接共存 ,需要的朋友可以参考下 2019-04-04
MySQL 5.7及8.0版本数据库的root密码遗忘的解决方法这篇文章主要介绍了MySQL 5.7及8.0版本数据库的root密码遗忘的解决办法,本文给大家介绍的非常详细,具有一定的参考借鉴价值,需要的朋友参考下吧 2019-12-12
MySQL 处理重复数据的方法(防止、删除)这篇文章主要介绍了MySQL 处理重复数据的方法,文中示例代码非常详细,帮助大家更好的理解和学习,感兴趣的朋友可以了解下 2020-07-07
sql格式化工具集合如果想要我们的SQL语句看起来很美观,除了自己平时注意外,还有一个懒人方法 2011-08-08
MySQL Community Server压缩包安装配置方法这篇文章主要为大家详细介绍了MySQL Community Server压缩包安装配置方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 2017-11-11
浅谈mysql数据库中的换行符与textarea中的换行符下面小编就为大家带来一篇浅谈mysql数据库中的换行符与textarea中的换行符。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧 2017-01-01
MySQL外键约束的实例讲解这篇文章主要介绍了MySQL外键约束的实例讲解,帮助大家更好的重温MySQL 外键约束的相关知识,感兴趣的朋友可以了解下 2020-11-11
windows下如何安装和启动MySQL本篇文章主要给大家介绍windows下如何安装和启动MySQL,需要的朋友跟着小编一起来学习啦 2015-08-08
MySQL MVVC多版本并发控制的实现详解在多版本并发控制中,为了保证数据操作在多线程过程中,保证事务隔离的机制,降低锁竞争的压力,保证较高的并发量。在每开启一个事务时,会生成一个事务的版本号,被操作的数据会生成一条新的数据行 2022-08-08
mysql启用skip-name-resolve模式时出现Warning的处理办法在优化MYSQL配置时,加入 skip-name-resolve ,在重新启动MYSQL时检查启动日志,发现有警告信息 2012-07-07
最新评论
大家感兴趣的内容
1mysql安装图解 mysql图文安装教程(详细说明)2Can''''t connect to MySQL serv3windows下MySQL5.6版本安装及配置过程附有截图和4Mysql字符串截取函数SUBSTRING的用法说明5mysql之TIMESTAMP(时间戳)用法详解6MySQL提示:The server quit withou7MySQL创建用户与授权方法8Mysql查看版本号的几种方式9MySQL——修改root密码的4种方法(以windows为10MySQL日期数据类型、时间类型使用总结
最近更新的内容
mysql 计算函数详情mysql select语句操作实例MySQL和Python交互的示例mysql group by 对多个字段进行分组操作MySQL数据库之存储过程 proceduremysqli多查询特性 实现多条sql语句查询MySQL创建用户与授权方法MySQL 自动清理binlog日志的方法MySql索引提高查询速度常用方法代码示例Ubuntu下启动、停止、重启MySQL,查看错误日志命令大全
常用在线小工具
微信
投稿
脚本任务
在线工具
关注微信公众号
关于我们 -
广告合作 -
联系我们 -
免责声明 -
网站地图 -
投诉建议 -
在线投稿
CopyRight 2006-2022 JB51.Net Inc All Rights Reserved. 脚本之家 版权所有