大表的 in 非常慢

吉普赛的歌 2018-01-11 10:41:38
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT a.*
from `bigTable` AS a
WHERE a.`id` in (SELECT pkValue
FROM `smallTable`
WHERE isProccessing = 1
AND finished = 0
);
COMMIT;
-- 上面的代码大约需要 8 分钟才能跑完;
--1. 改成 Exists 或 inner join 都还是很慢;
--2. 改成 in ( 'aaa','bbb','ccc' ) 实际值就快了;
--3. 大表表数据量:6909383 ,主键id数据类型: varchar(32), data_free: 8388608;
--4. 小表数据量 十条数据, 最多 100 条

请教各位大神, 除了先查出实际值之外, 还有什么办法可以改进?
...全文
550 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
没索引的情况,用这个应该和你用 IN ('a'. 'b') 相当
WHERE  FIND_IN_SET(a.`id`,(SELECT GROUP_CONCAT(pkValue)
                  FROM   `smallTable`
                  WHERE  isProccessing = 1
                         AND finished = 0
				))
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
看执行计划,大表是没索引啊
吉普赛的歌 2018-01-11
  • 打赏
  • 举报
回复
引用 2 楼 zjcxc 的回复:
试试再套一层
WHERE  a.`id` in (SELECT * FROM(SELECT pkValue
                  FROM   `smallTable`
                  WHERE  isProccessing = 1
                         AND finished = 0
					LIMIT 500
					) A
                );
套一层还是慢……
吉普赛的歌 2018-01-11
  • 打赏
  • 举报
回复
引用 1 楼 zjcxc 的回复:
explain 看下执行计划

吉普赛的歌 2018-01-11
  • 打赏
  • 举报
回复
引用 1 楼 zjcxc 的回复:
explain 看下执行计划
+----+-------------+-------------+------------+------+---------------+------+---------+------+---------+----------+-------------------------------------------------------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------------+------------+------+---------------+------+---------+------+---------+----------+-------------------------------------------------------------------+ | 1 | SIMPLE | smallTable | NULL | ALL | NULL | NULL | NULL | NULL | 29 | 3.45 | Using where; Start temporary | | 1 | SIMPLE | bigTable | NULL | ALL | NULL | NULL | NULL | NULL | 6289246 | 100 | Using where; End temporary; Using join buffer (Block Nested Loop) | +----+-------------+-------------+------------+------+---------------+------+---------+------+---------+----------+-------------------------------------------------------------------+
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
试试再套一层
WHERE  a.`id` in (SELECT * FROM(SELECT pkValue
                  FROM   `smallTable`
                  WHERE  isProccessing = 1
                         AND finished = 0
					LIMIT 500
					) A
                );
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
explain 看下执行计划
walkuere 2018-01-11
  • 打赏
  • 举报
回复
先把in写在临时表里面,然后in 临时表
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
可以先试试 use index(primary) 的执行计划
吉普赛的歌 2018-01-11
  • 打赏
  • 举报
回复
引用 10 楼 zjcxc 的回复:
确认下表结构是否有问题 show create table bigTable 如果没有问题,对表做下 REBUILD alter table bigtable force
对比过两个环境的 bigTable , 脚本基本一致。 alter table force 在测试环境需要 10 分钟左右, 生产环境暂时不好弄了, 晚上操作吧。
zjcxc 2018-01-11
  • 打赏
  • 举报
回复
确认下表结构是否有问题 show create table bigTable 如果没有问题,对表做下 REBUILD alter table bigtable force
吉普赛的歌 2018-01-11
  • 打赏
  • 举报
回复
引用 6 楼 zjcxc 的回复:
看执行计划,大表是没索引啊



测试环境又能走主键, 真是奇怪
吉普赛的歌 2018-01-11
  • 打赏
  • 举报
回复
引用 6 楼 zjcxc 的回复:
看执行计划,大表是没索引啊

56,675

社区成员

发帖
与我相关
我的任务
社区描述
MySQL相关内容讨论专区
社区管理员
  • MySQL
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧