如何解决MySQL left join 查询过慢的问题

发布时间:2021-07-07 14:42:26 作者:chen
来源:亿速云 阅读:1793

这篇文章主要讲解了“如何解决MySQL left join 查询过慢的问题”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何解决MySQL left join 查询过慢的问题”吧!

为什么会出现这个问题

在工作的过程中要把sql server 数据库中的几个表迁移到MySQL当中,以为数据库的方言和函数不同很多地方需要替换。在替换完成之后发现了一个问题,同样的一句关联查询语句在sql server总只需要0.2秒左右,在MySQL中却需要11秒左右。

MySQL sql

SELECT
	a.estate_name AS estateName,
	a.location AS estateLocation,
	IFNULL( b.挂牌数量, 0 ) AS numberListed,
	IFNULL( c.成交数量, 0 ) AS tradingVolume 
FROM
	(
	SELECT
		CONCAT( IFNULL( estate_name, '' ), IFNULL( area_name, '' ) ) AS ea,
		estate_name,
		MAX( location ) AS location 
	FROM
		beike_estate 
	GROUP BY
		estate_name,
		area_name 
	) AS a
	LEFT JOIN ( SELECT estate_name, COUNT( estate_name ) AS 挂牌数量 FROM beike_property WHERE estate_name IS NOT NULL GROUP BY estate_name ) AS b ON a.estate_name = b.estate_name
	LEFT JOIN (
	SELECT
		CONCAT( IFNULL( estate_name, '' ), IFNULL( area_name, '' ) ) AS ea,
		COUNT( estate_name ) AS 成交数量 
	FROM
		crawler_publish_property 
	WHERE
		`status` = 1 
	GROUP BY
	estate_name,
	area_name 
	) AS c ON a.ea = c.ea

sql server sql

SELECT
a.estate_name AS estateName,
a.location AS estateLocation,
ISNULL( b.挂牌数量, 0 ) AS numberListed,
ISNULL( c.成交数量, 0 ) AS tradingVolume 
FROM
	(
	SELECT
		ISNULL( estate_name, '' ) + ISNULL( area_name, '' ) AS ea,
		estate_name,
		MAX ( location ) AS location 
	FROM
		beike_estate 
	GROUP BY
		estate_name,
		area_name 
	) AS a
	LEFT JOIN ( SELECT estate_name, COUNT ( estate_name ) AS 挂牌数量 FROM beike_property WHERE estate_name IS NOT NULL GROUP BY estate_name ) AS b ON a.estate_name = b.estate_name
	LEFT JOIN (
	SELECT
		ISNULL( estate_name, '' ) + ISNULL( area_name, '' ) AS ea,
		COUNT ( estate_name ) AS 成交数量 
	FROM
		crawler_publish_property 
	WHERE
		[status] = 1 
	GROUP BY
		estate_name,
		area_name 
	) AS c ON a.ea = c.ea

可以看到2句sql除了函数上的区别,其他地方基本没有区别。

为什么使用MySQL lift join 查询速度过慢

既然没有区别为什么MySQL执行速度回这么慢呢?

查询过慢先想到的就是添加索引,但是这句sql是有三张表查询聚合出来的三张临时表关联查询,由于临时表并没有办法创建索引,我先在三张原始表上添加了索引,然后再次执行,速度还是和之前一样还是10多秒,并没有得到优化。使用 EXPLAIN 分析了一下这条sql,果然并没有使用到索引。

如何解决MySQL left join 查询过慢的问题

既然索引加不了,那就只能寻找其他解决方案了。经过一番百度了解到对于连表MySQL有2中join的算法分别是

Nested Loop Join算法

NLJ 算法:将驱动表/外部表的结果集作为循环基础数据,然后循环从该结果集每次一条获取数据作为下一个表的过滤条件查询数据,然后合并结果。如果有多表join,则将前面的表的结果集作为循环数据,取到每行再到联接的下一个表中循环匹配,获取结果集返回给客户端。

Block Nested Loop Join算法

BNL 算法:将外层循环的行/结果集存入join buffer, 内层循环的每一行与整个buffer中的记录做比较,从而减少内层循环的次数。

那么是不是因为lift join语句没有使用 Block Nested Loop算法所以很慢呢使用EXPLAIN分析发现使用的已经是Block Nested Loop算法了,所以也不是这个原因。

如何解决MySQL left join 查询过慢的问题

经过一番百度我了解到MySQL有一个Join_buffer_size的配置,这个配置是控制MySQ join 查询的缓存区大小的配置,Join_buffer_size的默认配置为128k。那么是不是由于这个缓存区太小导致查询速度过慢呢,我去查询了一下

如何解决MySQL left join 查询过慢的问题

结果显示缓存区域有256m的内存可供使用,也就说明查询速度慢并不是这个原因导致的。

经过一番百度,发现并不是因为其他原因,就是单纯的MySQL对join的处理效率不行。

解决方案

既然在数据库库陈无法进行优化,那么只能在server层进行优化了

既然是lift join那么只需要把左表进行分页查询再使用多个线程去查询,多个线程查询完成后再封装返回。

public List<BkFindEstateMsgDTO> findEstateMsg(){
	        List<BkFindEstateMsgDTO> list = beiKePropertyMapper.findEstateMsg();

        Integer i = beiKePropertyMapper.findEstateCount(); // 先查出总数目

        i = (i / 1000) + 1; // 计算需要几个线程

        Integer row = 1000;

        CountDownLatch countDownLatch = new CountDownLatch(i); // 线程计数器

        List<BkFindEstateMsgDTO> bkFindEstateMsgDTOS = new ArrayList<>();


        for (int j = 0; j < i; j++) {
            int j1 = j;
            executorService.execute(() -> { // 多线程同时查询
                List<BkFindEstateMsgDTO> list = beiKePropertyMapper.findEstateMsg1(j1*row,row);
                bkFindEstateMsgDTOS.addAll(list);
                countDownLatch.countDown(); // 提交计数器
            });
        }
	try {
          countDownLatch.await(); // 所有线程完成提交
        } catch (Exception e) {
            e.printStackTrace();
        }
}

使用多线程之后只需要2秒左右就可执行完毕。

如果不想线程太多可以将sql拆分为2个lift join的查询语句,使用2个线程同时进行查询,第二条查询语句返回map集合,将需要连表的条件作为key,查询结果作为value,查询出来之后遍历第一个结果集合通过key取出对应的value set到对应的对象当中即可。这样最后的查询结果在6秒左右。

返回指定的列作为map集合的key只需要在dao层接口方法上添加@MapKey("")注解即可。

感谢各位的阅读,以上就是“如何解决MySQL left join 查询过慢的问题”的内容了,经过本文的学习后,相信大家对如何解决MySQL left join 查询过慢的问题这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是亿速云,小编将为大家推送更多相关知识点的文章,欢迎关注!

推荐阅读:
  1. MYSQL的多表查询
  2. MySQL联表查询中left-join常见问题

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

mysql

上一篇:JS怎么判断时间段

下一篇:BootStrap中如何实现Table复选框默认选中功能

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》