前往小程序,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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Android开发之漫漫长途 XIV——ListView
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!
LoveWFan
2018/08/07
9460
Android开发之漫漫长途 XIV——ListView
Android--ListView复用机制源码分析
ListView是谷歌官方的一个自定义组件,用于列表展示,其中最重要的是Adapter设配器,设配器模式的设计为它带来了极大的性能提升,一方面,内存中只有我们看的到的ItemView被创建(对比ScrollView:有多少子控件就内存中创建多少子控件),另一方面,对ItemView缓存,以便滑动时复用 既然ListView是自定义组件,我们首先找到它的Measure方法 protected void onMeasure(int widthMeasureSpec, int heightMeasureS
aruba
2020/07/03
5450
Android ListView功能扩展,实现高性能的瀑布流布局
本文介绍了如何基于Android平台实现瀑布流布局,并给出了具体的代码示例。首先介绍了什么是瀑布流布局以及其特点,然后详细讲解了Android平台如何实现瀑布流布局,最后通过一个具体的实例展示了瀑布流布局的应用场景和实现方法。
用户1158055
2018/01/08
2.1K0
Android ListView功能扩展,实现高性能的瀑布流布局
实习入职第二十天:从setRecyclerListener看listView回收机制
关于这个  setRecyclerListener函数在解决   listView滑出屏幕(包括向上滑出和向下滑出)处理相关UI操作或者释放相关资源,真的很好用,
wust小吴
2019/07/08
9880
最熟悉的陌生人:ListView 中的观察者模式
张拭心 shixinzhang
2018/01/05
8930
最熟悉的陌生人:ListView 中的观察者模式
设计模式学习之适配器模式
在我们平时的开发过程中,适配器模式可以说是经常能见到的设计模式,ListView 和 RecyclerView 的 Adapter 就是典型的适配器模式,当我们在开发时,碰到要在两个完全没有关系的类之间进行交互,第一个解决方案是修改各自类的接口,但是如果无法修改源代码或者其他原因导致无法更改接口,此时怎么办?这种情况我们往往会使用一个 Adapter ,在这两个接口之间创建一个粘合剂接口,将原本无法协作的类进行兼容,而且不用修改原来两个模块的代码,符合开闭原则。
老马的编程之旅
2022/06/22
3770
设计模式学习之适配器模式
ListView的一个典型crash cannot be cast to android.widget.AbsListView$LayoutParams1. 背景2. 为什么会出现crash3.
1. 背景 一个新版本的代码,在4.x版本进入某个页面的时候,必现crash。看到必现,心情就放松了一半。 大致的crash信息如下: FATAL EXCEPTION: main java.lang.ClassCastException: android.support.v4.view.ViewPager$LayoutParams cannot be cast to android.widget.AbsListView$LayoutParams at android.widget.ListView.se
用户1127566
2018/06/06
1.3K0
ListView之多种类型Item
一般而言,listview每个item的样式是一样的,但也有很多应用场景下不同位置的item需要不同的样式。
全栈程序员站长
2022/09/06
5030
ListView之多种类型Item
笔记25 | 通过自定义VIEW实现一个圆盘转动UI
实现效果 主要代码 自定义CircleLayout package com.duguang.baseanimation.ui.customview.circlemenu; /* * Copyrig
项勇
2018/06/19
7830
BaseAdapter的notifyDataSetChanged方法[通俗易懂]
都用过 BaseAdapter的notifyDataSetChanged()方法,用法很简单,当BaseAdapter的数据更新了,需要更改显示,这时候就要调用notifyDataSetChanged()方法来更新数据,当然你可以用一种比较恶心的方式,在你所使用的AdapterView(这里是指AdapterView的子类,ListView,GridView,Gallery等等),调setAdapter()方法。好好分析一下如何使用以及为什么要使用notifyDataSetChanged方法。
全栈程序员站长
2022/09/12
1.2K0
BaseAdapter的notifyDataSetChanged方法[通俗易懂]
Android ListView那些事
ListView是我们在开发Android程序时用得比较多的一种widget,通常用来展示多条数据,这里,我对ListView的一些功能点作一个简单介绍。
全栈程序员站长
2022/09/15
4930
Android开发之漫漫长途 XV——RecyclerView
该文章是一个系列文章,是本人在Android开发的漫漫长途上的一点感想和记录,我会尽量按照先易后难的顺序进行编写该系列。该系列引用了《Android开发艺术探索》以及《深入理解Android 卷Ⅰ,Ⅱ,Ⅲ》中的相关知识,另外也借鉴了其他的优质博客,在此向各位大神表示感谢,膜拜!!!
LoveWFan
2018/08/07
2.3K0
Android开发之漫漫长途 XV——RecyclerView
Android TV开发总结【RecycleView】
在TV开发中RecycleView的使用是最让人头疼的经常会出现焦点丢失。因为当item未显示时不能获取焦点。所以当我们按上下键时经常丢失焦点或者焦点乱跳。要解决这个问题我们必须要手动控制RecyclerView 的按键和焦点移动。
先知先觉
2019/01/21
2.8K0
1-VIII--ViewPager的基本使用
零、前言 [1].ViewPager顾名思义是将若干视图一页一页的展现 [2].ViewPager和Fragment郎才女貌,天造之合,在加个TabLayout简直和睦一家人 [3].本文介绍V
张风捷特烈
2018/09/26
8410
Android RecyclerView 使用完全解析 体验艺术般的控件
RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用。 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、GridView。
wust小吴
2019/07/08
1.6K0
StickyListHeaders的用法说明(带字母索引条)
有些同学可能没用过这个SckyListHeadersListView 先发个效果图,图片是从别的地方拷贝过来的
再见孙悟空_
2023/02/10
9100
StickyListHeaders的用法说明(带字母索引条)
解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题
我们先看一个效果,问题说的就是中间的Grid效果在Scrollview 嵌套recyclerview显示问题,在Android Api 24是好的,不过在5,1,1版本(api 22)缺出现了问题 最
xiangzhihong
2018/02/05
3.5K0
解决Scrollview 嵌套recyclerview不能显示,高度不正常的问题
打造Android微信朋友圈下拉刷新控件
我们初步分析下,界面上主要有二个控件,一个彩虹状的圆形LoadingView,一个是ListView,那么我大致可以有下面三个步骤:
三好码农
2018/09/11
1.9K0
打造Android微信朋友圈下拉刷新控件
解决水平ListView在ScrollView中出现的滑动冲突
解决的问题有两个:  1)实现水平滑动的ListView。重写AdapterView,上代码:  Java代码   package com.liucanwen.horizontallistview.view;   import java.util.LinkedList;   import java.util.Queue;   import android.content.Context;   import android.database.DataSetObserver;   i
xiangzhihong
2018/02/01
1.7K0
解决水平ListView在ScrollView中出现的滑动冲突
Android自定义组合控件---教你如何自定义下拉刷新和左滑删除
版权声明:本文为博主原创文章,转载请标明出处。 https://blog.csdn.net/lyhhj/article/details/80122918
Hankkin
2018/09/06
1.4K0
Android自定义组合控件---教你如何自定义下拉刷新和左滑删除
推荐阅读
相关推荐
Android开发之漫漫长途 XIV——ListView
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档