Mysql多张千万级数据量连表查询优化记录

1.背景

慢查询sql:

SELECT
	info.id,
	info.create_time,
	info.modify_time,
	info.prizes_info_id,
	info.prize_name,
	info.award_time,
	info.award_status,
	info.winning_time,
	info.join_time,
	info.check_status,
	info.award_type,
	info.award_type_name,
	member.mobile AS member_mobile,
	member.NAME AS member_real_name,
	card_info.card_no AS member_card_no,
	mall_info.NAME AS mall_name,
	mall_info.id AS mall_id,
	LEVEL.member_level AS member_level 
FROM
	mob_prizes_info.prizes_record_info AS info
	LEFT JOIN member_info AS member ON info.member_id = member.id
	LEFT JOIN card_info AS card_info ON info.member_id = card_info.vip_uid
	LEFT JOIN member_level AS LEVEL ON LEVEL.id = member.LEVEL 
	LEFT JOIN activity_base_info AS activity ON info.activity_id = activity.id
	LEFT JOIN event_promotion_award_config AS event_promotion ON info.activity_id = event_promotion.id
	LEFT JOIN mall_info AS mall_info ON mall_info.id = (
	CASE WHEN info.activity_mall_id IS NOT NULL THEN
			info.activity_mall_id 
			WHEN activity.mall_id IS NULL THEN
			event_promotion.mall_id ELSE activity.mall_id 
		END 
		) 
	WHERE
		info.join_time >= 1715961600 
		AND ( info.activity_mall_id = 'xx' OR activity.mall_id = 'xx' OR event_promotion.mall_id = 'BwvfX3ymNCddIUfG' ) 
		AND activity.CODE IN ( 'xx', 'xx' ) 
	ORDER BY
		info.join_time DESC 
	LIMIT 0,
	10

查询消耗:40s 左右

各表数据量:

数量级
mob_prizes_info16473811 主表
card_info11783047
member_info17275533
2.优化思路

1.分析索引:
在这里插入图片描述

检查查询条件join_time 是否是索引,发现join_time不是索引,但是winning_time是已经是索引

​ 把查询条件更换为winning_time,发下查询时间大大优化,这里可以定位到慢查询的原因:未使用索引

​ 解决方法:

  1. 给join_time 设置索引,怎么表的存储,空间换时间

  2. 使用winning_time作为查询条件,需要给业务沟通(这里查询统计数量一致,可能排序不一致,业务要求不严格可以使用)

    经过沟通,需要使用join_time 字段,所以选择使用方式1解决

可能这里你认为问题已经解决,但是还是存在问题,分页查询count查询依然特别慢

在这里插入图片描述
在这里插入图片描述

查询时间在20秒左右,所以也需要优化

再次分析sql:
在这里插入图片描述
在这里插入图片描述

导致慢sql原因:当你关联数据量大的表如 membercard_info 时,如果这些表的索引策略不合理或者连接键上的索引未被有效利用,会导致查询性能显著下降。数据库查询优化器通常会根据统计信息来选择最佳的连接顺序,但是少数据优化器不知道你的数据量,所以需要手处理

解决方法:

  1. 连接顺序和策略

    • 数据库查询优化器通常会根据统计信息来选择最佳的连接顺序。如果统计信息过时,或者优化器的选择不是最优的,可能需要手动干预。

    • 使用 STRAIGHT_JOIN 强制查询按照你指定的顺序执行,有时可以改进性能,尤其是在处理大表时。

      SELECT
      COUNT(info.id)
      FROM
      	mob_prizes_info.prizes_record_info AS info
      	LEFT JOIN mob_prizes_info.activity_base_info AS activity ON info.activity_id = activity.id
      	LEFT JOIN mob_promotion.event_promotion_award_config AS event_promotion ON info.activity_id = event_promotion.id
      	LEFT JOIN mob_base_info.mall_info AS mall_info ON mall_info.id = (
      	CASE
      			WHEN info.activity_mall_id IS NOT NULL THEN
      			info.activity_mall_id 
      			WHEN activity.mall_id IS NULL THEN
      			event_promotion.mall_id ELSE activity.mall_id 
      		END 
      		) 
      		STRAIGHT_JOIN  member_info AS member ON info.member_id = member.id
      		STRAIGHT_JOIN member_level AS LEVEL ON LEVEL.id = member.LEVEL 
      		STRAIGHT_JOIN  card_info AS card_info ON info.member_id = card_info.vip_uid
      	WHERE
      		info.join_time >= 1715961600 
      		AND ( info.activity_mall_id = '1' OR activity.mall_id = '1' OR event_promotion.mall_id = '1' ) 
      		AND activity.CODE IN ( '1', '1' ) 
      

      在这里插入图片描述

      0.43 优化非常明显

  2. 针对业务:发现该查询是多个菜单使用,但是部分字段和表在此菜单不需要关联,针对这个菜单不需要member_level,所以这里只需要重写一个sql查询,去掉member_level关联信息即可

    SELECT
    COUNT(info.id)
    FROM
    	prizes_record_info AS info
    	LEFT JOIN activity_base_info AS activity ON info.activity_id = activity.id
    	LEFT JOIN event_promotion_award_config AS event_promotion ON info.activity_id = event_promotion.id
    	LEFT JOIN mall_info AS mall_info ON mall_info.id = (
    	CASE
    			WHEN info.activity_mall_id IS NOT NULL THEN
    			info.activity_mall_id 
    			WHEN activity.mall_id IS NULL THEN
    			event_promotion.mall_id ELSE activity.mall_id 
    		END 
    		) 
    		LEFT JOIN  member_info AS member ON info.member_id = member.id
    		LEFT JOIN member_level AS LEVEL ON LEVEL.id = member.LEVEL 
    		LEFT JOIN  card_info AS card_info ON info.member_id = card_info.vip_uid
    	WHERE
    		info.join_time >= 1715961600 
    		AND ( info.activity_mall_id = '1' OR activity.mall_id = '1' OR event_promotion.mall_id = '1' ) 
    		AND activity.CODE IN ( '1', '1' ) 
    

    在这里插入图片描述

0.362

以上算是完全解决全部问题

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MySQL是一款常用的关系型数据库管理系统,当数据达到百万级时,使用常规的分页查询方法可能会导致查询效率低下,因此需要一些优化建议。 1. 使用索引:在分页查询中,使用合适的索引可以大大提高查询速度。对于分页查询,需要对页码(如LIMIT中的offset)以及排序字段进行索引,以减小查询范围。 2. 建立分区:对于大数据,可以根据某个字段对进行分区,将数据分散存储在多个磁盘上,提高查询效率。 3. 避免全扫描:尽避免使用SELECT *,只选择需要的字段,减少数据传输优化查询性能。 4. 使用缓存:使用缓存技术,如Memcached或Redis等,在查询结果比较频繁且变化不大的情况下,可以将查询结果缓存起来,减少数据库的压力。 5. 分批查询:可以将大的查询结果分批获取,每次查询一部分数据,实现逐步加载,减少数据库的负载。 6. 合理使用内存:增大MySQL的缓冲池大小,尽数据存储在内存中,减少磁盘IO,提高查询性能。 7. 优化查询语句:合理编写查询语句,避免复杂的JOIN、子查询等操作,可以考虑优化查询语句的写法,减少不必要的计算和查询。 8. 使用查询缓存:对于一些经常被查询数据,可以开启查询缓存功能,将查询结果缓存起来,提高查询性能。 总之,对于百万级数据的分页查询,需要综合考虑以上建议,并根据具体情况进行优化,合理地使用索引、缓存等技术,以提高查询效率和系统性能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值