Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >MySQL表连接优化的初步分析

MySQL表连接优化的初步分析

作者头像
jeanron100
发布于 2018-08-22 06:35:19
发布于 2018-08-22 06:35:19
1.6K00
代码可运行
举报
运行总次数:0
代码可运行

每每一些很深刻的优化案例时,就会无比想念Oracle里的优化技巧,因为无论是从工具还是信息,都会丰富许多。

数据库技术就是这么一路走过来,MySQL的优化器也是,所以在MySQL最流行的情况下,我只能更多的去摸清楚优化器里的一些实现差异。

还是昨天的那个SQL优化案例,我会从另外几个维度来说下优化的思路。

伪SQL如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    update big_table,
    (xxxxxx ) small_table
    set xxxxx
    where xxxxxx;
看起来这个语句很简单,如果展开,完整的SQL如下:
UPDATE 
 digital_test.comprehensive_orders co , --千万级大表
 ( SELECT 
    uoi.order_code ,
    MAX(uoi.item_stat) AS costat ,
    SUM(uoi.winning_gold) AS winningGold ,
    SUM(uoi.winning_gold-uoi.item_price) as profit 
   FROM  
   test.user_order_items uoi ,  --近千万级大表
   ( SELECT DISTINCT a.order_code FROM test.user_order_items a WHERE a.match_id=35303 AND a.item_pid=51 AND a.item_stat>0 )

    AS temp0 
   WHERE uoi.order_code=temp0.order_code GROUP BY uoi.order_code HAVING bit_and(uoi.item_stat>>1)!=0  

 ) 
   AS temp1 
   SET 
    co.co_stat=(CASE WHEN temp1.coStat IN (6,9) THEN 4 ELSE temp1.coStat END),
    co.co_winning_gold=temp1.winningGold, co.co_test_draw_time='2018-08-07 16:20:45', 
    co.co_share_income_outcome = CASE WHEN co.co_order_type=4 THEN ( CASE WHEN temp1.profit>0 THEN ROUND(ifnull(co.co_share_payoff_ratio,0) * temp1.profit) ELSE 0 END ) ELSE 0 END ,
    co.co_award_id=35309 
WHERE co.co_order_code=temp1.order_code AND co.co_stat=1

我从几个维度来简单说一下,核心的优化思想还是“平衡”

  1. 首先我们定位到最初的解决方案。

伪SQL可以更加丰富一些。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
UPDATE 
 digital_test.comprehensive_orders co ,  
 ( SELECT 
    xxxx
   FROM  
   test.user_order_items uoi ,
   ( SELECT DISTINCT a.order_code FROM test.user_order_items a WHERE a.match_id=35303 AND a.item_pid=51 AND a.item_stat>0 )

    AS temp0 
   WHERE uoi.order_code=temp0.order_code GROUP BY uoi.order_code HAVING bit_and(uoi.item_stat>>1)!=0  

 ) 
   AS temp1 
   SET 
   xxxx
WHERE co.co_order_code=temp1.order_code AND co.co_stat=1

其中temp1里的查询过滤的结果集是个位数,而外层的表digital_test.comprehensive_orders数据上千万,但是关联的条件是走主键的。

我们画个图来说。

上面这种情况其实MySQL是很容易区分的,难就难在这个情况真实情况是这样的。

如果碰到这种情况,MySQL优化器就有点懵了。这两个大表自己关联,结果集到底有多大,因为没有更丰富的信息,要定位还是有些难的。

所以从执行计划来看,为什么性能差,最后优化器的判断是对两个大表做了全表扫描。

所以我的思路是通过对where条件的过滤来做的,既然他没法确定更小的结果集,那么我就在where部分过滤,SQL肯定会优先处理where的部分。得到的是小的结果集,自然压力就小了。

还有没有更好的方案呢,同事也提供了一些思路,最后的方案是根据他的建议来做的。

这个改进是怎么做的呢, 带颜色的部分就是改动的地方。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
UPDATE digital_test.comprehensive_orders co,
    (
    SELECT xxxxx
    FROM 
    (
    SELECT  a.order_code
    FROM test.user_order_items a
    WHERE a.match_id=35303
    AND a.item_pid=51
    AND a.item_stat>0
    ) AS temp0  join test.user_order_items uoi 
    on uoi.order_code=temp0.order_code
    GROUP BY uoi.order_code HAVING bit_and(uoi.item_stat>>1)!=0
     ) AS temp1
SET
 xxxxx
WHERE co.co_order_code=temp1.order_code
            AND co.co_stat=1 ;

可以看到这种改法,没有添加额外的SQL逻辑,把原来的表关联改为了join的方式,效果是立竿见影。

这里的改动思路是把原来的大表小表关联,改为小表大表关联,然后改为join的写法。

那么这里就有两个问题,

  1. 同样是表关联,小表大表关联和大表小表关联,这种写法在MySQL那么重要吗?
  2. 是否join的写法效果要更好一些?

要验证这两个问题,其实也不难。我们使用如下的SQL来验证。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
UPDATE 
 digital_test.comprehensive_orders co ,
 ( SELECT 
   xxxxx
   FROM 
   ( SELECT DISTINCT a.order_code FROM test.user_order_items a WHERE a.match_id=35303 AND a.item_pid=51 AND a.item_stat>0 )
    AS temp0 ,
 test.user_order_items uoi 
   WHERE uoi.order_code=temp0.order_code GROUP BY uoi.order_code HAVING bit_and(uoi.item_stat>>1)!=0  
 ) 
   AS temp1 
   SET 
   xxxx
WHERE co.co_order_code=temp1.order_code AND co.co_stat=1

这种改法简直天然无公害,执行效率也是杠杠的。在这个场景下,确实顺序还是有很大的关联的。

然后第二个问题,是否join的方式要更好一些?

我们可以把表关联写为大表 join 小表,看看效果如何。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
UPDATE 
 digital_test.comprehensive_orders co ,
 (SELECTxxxx
    FROM 
       test.user_order_items uoi join(
    SELECT  a.order_code
    FROM test.user_order_items a
    WHERE a.match_id=35303
    AND a.item_pid=51
    AND a.item_stat>0
    ) AS temp0
  on uoi.order_code=temp0.order_code
    GROUP BY uoi.order_code HAVING bit_and(uoi.item_stat>>1)!=0 
 ) 
   AS temp1 
   SET 
  xxxxx
WHERE co.co_order_code=temp1.order_code AND co.co_stat=1

这种情况下,SQL的性能是比较差的,大概1分钟后才有反应。

所以在这种场景下,join的写法明显没有特殊的改进。

我们简单总结一下,在这个SQL优化场景中,为了得到更好的性能,需要做到一个平衡,即小表和大表的关联方式,效率是最佳的,至于你是写成join还是逗号分隔的表关联,从目前的测试来看,差别不大。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2018-08-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 杨建荣的学习笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【测试SQLite】测试SQLite支持的SQL语句分类
为了全面测试SQLite支持的SQL语句,需要设计一个包含多种类型的表结构,并编写各种SQL语句来测试这些功能。目前按照以下分类进行测试:
SarPro
2024/05/24
4440
【测试SQLite】测试SQLite支持的SQL语句分类
MySQL 5.5迁移到5.7的性能问题排查案例
最近和同事排查了一个MySQL的SQL性能问题。问题的背景是有一个业务的数据库从MySQL 5.5迁移到了MySQL 5.7,原来在5.5中有一个SQL秒级就能完成,但是在5.7版本中执行时间长了好多,业务也产生了延迟。
jeanron100
2018/08/22
1.1K0
MySQL 5.5迁移到5.7的性能问题排查案例
「SQL面试题库」 No_71 市场分析 II
写一个 SQL 查询确定每一个用户按日期顺序卖出的第二件商品的品牌是否是他们最喜爱的品牌。如果一个用户卖出少于两件商品,查询的结果是
不吃西红柿
2023/05/23
1570
日常开发常见MySQL性能优化策略及应用场景
在电子商务平台的日常运营中,经常需要根据用户的订单状态和日期进行查询。随着订单量的增加,查询响应时间变长,影响报表生成和订单处理效率。
GeekLiHua
2024/08/19
2230
日常开发常见MySQL性能优化策略及应用场景
LeetCode MySQL 1158. 市场分析 I
请写出一条SQL语句以查询每个用户的注册日期和在 2019 年作为买家的订单总数。
Michael阿明
2021/02/19
4830
MySQL Prepare后语句查询性能降低 源码bug排查分析
源自于业务上遇到的一个先将某个语句Prepare再Execute查询效率很低的问题,而将查询中的参数直接嵌入到SQL语句内并以文本形式执行,则执行反而变得很快。
Miigon
2022/11/25
1.5K0
MySQL Prepare后语句查询性能降低 源码bug排查分析
浅谈 AnalyticDB SQL 优化「建议收藏」
数据库性能优化需要从多个方面进行综合考虑。 例如:系统资源是否充足、资源模型的设计(高性能 vs 大存储)、表的设计以及规划、SQL改写和优化等等,本文只要介绍adb sql的优化
全栈程序员站长
2022/09/29
1.2K0
浅谈 AnalyticDB SQL 优化「建议收藏」
LeetCode MySQL 1159. 市场分析 II(rank+over)
写一个 SQL 查询确定每一个用户按日期顺序卖出的第二件商品的品牌是否是他们最喜爱的品牌。
Michael阿明
2021/02/19
3730
MySQL千万大表优化实践
前段时间笔者遇到一个复杂的慢查询,今天有空便进行了整理,以便日后回顾。举一个相似的业务场景的例子。以文章评论为例,查询20191201~20191231日期间发表的经济科技类别的文章,同时需要显示这些文章的热评数目
王知无-import_bigdata
2020/09/25
2K0
MySQL千万大表优化实践
Mybatis笔记二
注意:因为一个订单信息只会是一个人下的订单,所以从查询订单信息出发关联查询用户信息为一对一查询。如果从用户信息出发查询用户下的订单信息则为一对多查询,因为一个用户可以下多个订单。
HUC思梦
2020/09/03
4920
Mybatis笔记二
故障分析 | MySQL 派生表优化
这是一个统计类的 SQL,直接执行跑了好几个小时都没有结束,所以暂时不知道实际耗时,因为实在是太久了~
爱可生开源社区
2020/03/13
1.5K0
自己设计一个 JAVA + MyBatis 解析实体类多表通用查询
首先想清楚实体类与数据表的映射关系, 如 表名 主键 逻辑删除 ... (按需求自行添加) //那么我们需要先自定义如下几个注解 ​ //用于表示实体类对应的数据表 @TableName(value = "数据表名") //用于表示实体主键 @TableId //用于表示字段为逻辑删除 @TableLogic 现在已经可以通过实体类描述一张数据表了,那么我们来想一下如何优雅的想一个使用方式吧 首先我们需要表示查询的字段有哪些?如何表示呢? 如何关联表 如何定义查询条件 排序 如何分组等等 ...
工具人
2020/07/17
1.4K0
PawSQL独家秘笈:表连接消除优化让SQL性能翻倍
在数据库优化的世界里,有一个鲜为人知但威力巨大的技巧 - 连接消除(Join Elimination)。本文将为您揭示这个可以显著提升SQL查询性能的秘密武器。
PawSQL
2024/08/20
1390
PawSQL独家秘笈:表连接消除优化让SQL性能翻倍
做 SQL 性能优化真是让人干瞪眼
很多大数据计算都是用 SQL 实现的,跑得慢时就要去优化 SQL,但常常碰到让人干瞪眼的情况。
小小詹同学
2021/12/13
5520
MySQL连接的原理⭐️4种优化连接的手段性能提升240%🚀
上两篇文章我们说到MySQL优化回表的三种方式:索引条件下推ICP、多范围读取MRR与覆盖索引
菜菜的后端私房菜
2024/06/14
3751
MySQL 性能优化的 9 种姿势,面试再也不怕了!
Mysql是一种关系型数据库,可以很好地支持大数据量的存储,但是一般来说,数据库中的表越小,在它上面执行的查询也就越快。因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度舍得尽可能小。
程序员小猿
2021/11/23
1.1K0
全面透彻,MySQL 正确的慢查询处理姿势
在过去的半年时间里,研发团队内部尝试抓了一波儿慢查询SQL跟进处理率。发现有些同学对于慢查询处理的思路就是看看有没有用到索引,没有用到就试图加一个,实在不行就甩锅给这种情况是历史设计问题或者自行判定为用户特殊操作下触发的小概率事件,随即便申请豁免掉... 其实问题没有根本上解决。
架构精进之路
2024/05/29
1.9K0
全面透彻,MySQL 正确的慢查询处理姿势
9个SQL优化技巧
大多数的接口性能问题,很多情况下都是SQL问题,在工作中,我们也会定期对慢SQL进行优化,以提高接口性能。这里总结一下常见的优化方向和策略。
科技新语
2024/05/21
2350
9个SQL优化技巧
MySQL 系列教程之(八)DQL:子查询与表连接
订单存储在两个表中。对于包含订单号、客户ID、订单日期的每个订单,orders表存储一行。
ruochen
2021/08/15
1.6K0
MySQL 系列教程之(八)DQL:子查询与表连接
MySQL怎样优化千万级数据
这里讨论的情况是在MySQL一张表的数据达到千万级别。表设计很烂,业务统计规则又不允许把sql拆成多个子查询。
闻说社
2024/05/21
1990
MySQL怎样优化千万级数据
相关推荐
【测试SQLite】测试SQLite支持的SQL语句分类
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验