• 问题:

近日,线上MySQL查出一个慢sql,每次都要查询1000ms以上,严重影响用户体验

今得空去诊断一番,记录如下:

sql原句:

  1. SELECT r.object_id AS cardId, count(1) AS attachs FROM hzresource_object r
  2. LEFT JOIN
  3. ( SELECT card_id FROM card_member WHERE user_id = #uid# and card_member.deleted=0
  4. UNION
  5. SELECT card_id FROM card_subscribed where user_id = #uid# and card_subscribed.deleted=0
  6. ) m ON r.object_id = m.card_id
  7. WHERE r.object_type = #objectType# AND r.deleted = 0
  8. GROUP BY r.object_id;
  • 解决问题:

由于对数据库优化一知半解,完全无从下手,只能求助度娘和谷哥了,试验了各种方法,都不见效果

几番周折之后,最终把注意力集中到了临时表上,因为explain查看执行计划,可以看到Using temporary

MySQL在执行SQL查询时可能会用到临时表,一般情况下,用到临时表就意味着性能较低。

于是想办法修改sql语句,摒弃临时表,修改如下:

  1. SELECT r.object_id AS cardId, count(1) AS attachs FROM hzresource_object r
  2. WHERE r.object_type = #objectType#  AND r.deleted = 0 and r.object_id in (
  3. SELECT card_id FROM card_member WHERE user_id = #uid# and card_member.deleted=0
  4. UNION
  5. SELECT card_id FROM card_subscribed where user_id = #uid# and card_subscribed.deleted=0
  6. )
  7. GROUP BY r.object_id;

即把语句给拆分成两个sql语,用in操作拼接

  • 本机测试:

优化前执行时间1040ms,优化后执行时间:85ms,执行速度是原来的12倍多!赞

  • PS:

常理我们都会排斥用in操作,用union替换,那为什么这里用in会更快呢?

带着问题,接着去网上找,原来:

sql执行会生成一个巨大的临时表,当内存放不下时,要全部copy 到磁盘,导致IO飙升,时间开销增大。

额外收获知识收藏如下:

  • 临时表存储

MySQL临时表分为“内存临时表”和“磁盘临时表”,其中内存临时表使用MySQL的MEMORY存储引擎,磁盘临时表使用MySQL的MyISAM存储引擎;
一般情况下,MySQL会先创建内存临时表,但内存临时表超过配置指定的值后,MySQL会将内存临时表导出到磁盘临时表;

  • 使用临时表的场景

1)ORDER BY子句和GROUP BY子句不同, 例如:ORDERY BY price GROUP BY name;
2)在JOIN查询中,ORDER BY或者GROUP BY使用了不是第一个表的列 例如:SELECT * from TableA, TableB ORDER BY TableA.price GROUP by TableB.name
3)ORDER BY中使用了DISTINCT关键字 ORDERY BY DISTINCT(price)
4)SELECT语句中指定了SQL_SMALL_RESULT关键字 SQL_SMALL_RESULT的意思就是告诉MySQL,结果会很小,请直接使用内存临时表,不需要使用索引排序 SQL_SMALL_RESULT必须和GROUP BY、DISTINCT或DISTINCTROW一起使用 一般情况下,我们没有必要使用这个选项,让MySQL服务器选择即可。

  • 直接使用磁盘临时表的场景

1)表包含TEXT或者BLOB列;
2)GROUP BY 或者 DISTINCT 子句中包含长度大于512字节的列;
3)使用UNION或者UNION ALL时,SELECT子句中包含大于512字节的列;

  • 表的设计原则

使用临时表一般都意味着性能比较低,特别是使用磁盘临时表,性能更慢,因此我们在实际应用中应该尽量避免临时表的使用。 常见的避免临时表的方法有:
1)创建索引:在ORDER BY或者GROUP BY的列上创建索引;
2)分拆很长的列:一般情况下,TEXT、BLOB,大于512字节的字符串,基本上都是为了显示信息,而不会用于查询条件, 因此表设计的时候,应该将这些列独立到另外一张表。

  • SQL优化

如果表的设计已经确定,修改比较困难,那么也可以通过优化SQL语句来减少临时表的大小,以提升SQL执行效率。
常见的优化SQL语句方法如下:
1)拆分SQL语句
临时表主要是用于排序和分组,很多业务都是要求排序后再取出详细的分页数据,这种情况下可以将排序和取出详细数据拆分成不同的SQL,以降低排序或分组时临时表的大小,提升排序和分组的效率,我们的案例就是采用这种方法。
2)优化业务,去掉排序分组等操作
有时候业务其实并不需要排序或分组,仅仅是为了好看或者阅读方便而进行了排序,例如数据导出、数据查询等操作,这种情况下去掉排序和分组对业务也没有多大影响。

  • 如何判断使用了临时表?

使用explain查看执行计划,Extra列看到Using temporary就意味着使用了临时表。

  • 小结:

可见, 完全颠覆了对in操作符的认识,凡事儿都是要分情况讨论的

mysql临时表产生的执行效率问题改进(转)的更多相关文章

  1. mySQL数据库Sql语句执行效率检查--Explain命令

    mysql性能的检查和调优方法 Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 果,可以帮助选择更好的 ...

  2. MySQL查看SQL语句执行效率

    Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看 SQL 语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好 ...

  3. MySQL查看SQL语句执行效率(转)

    Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看 SQL 语句的执行效 果,可以帮助选择更好的索引和优化查询语句,写出更好 ...

  4. mysql 查看语句的执行效率

    EXPLAIN 一.用途: 1.什么时候必须为表加入索引以得到一个使用索引找到记得的更快的select 2.知道优化器是否以一个最佳次序联结表. <官方的关于explain的文档在http:// ...

  5. mysql is not null 执行效率低

    a表字段类型为int b表字段类型为varchar a left join b时如果查询条件是is not null,效率很快,is  null 效率很低 后来两者改为同类型 int,效率很高

  6. mysql优化(三)–explain分析sql语句执行效率

    mysql优化(三)–explain分析sql语句执行效率 mushu 发布于 11个月前 (06-04) 分类:Mysql 阅读(651) 评论(0) Explain命令在解决数据库性能上是第一推荐 ...

  7. Mysql explain分析sql语句执行效率

    mysql优化–explain分析sql语句执行效率 Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看SQL语句的执行效 ...

  8. Mysql 定位执行效率低的sql 语句

    一.通过MySQL慢查询日志定位执行效率低的SQL语句. MySQL通过慢查询日志定位那些执行效率较低的SQL 语句,用--log-slow-queries[=file_name]选项启动时,mysq ...

  9. php中使用mysqli和pdo扩展,测试mysql数据库的执行效率。

    <?php /** * 测试pdo和mysqli的执行效率 */ header("Content-type:text/html;charset=utf-8"); //通过pd ...

随机推荐

  1. javascript弹层

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  2. Android studio导入eclipse项目遇到的错误解决方案

    Error:Execution failed for task ':app:compileDebugJavaWithJavac'. > Compilation failed; see the c ...

  3. j解决sparkr中使用某些r的原生函数 发生错误Error: class(objId) == "jobj" is not TRUE的问题

    Create table function in Spark in R not working João_Andre  (3) 询问的问题 | 2016年12月10日 06:03BLUEMIXRSPA ...

  4. Linux 安装 Oracle 11g R2

    一.安装环境 Linux服务器:Centos 6.4 64位 Oracle服务器:Oracle11gR2 64位 二.系统要求 Linux安装Oracle系统要求 系统要求 说明 内存 必须高于1G的 ...

  5. Network In Network——卷积神经网络的革新

    Network In Network 是13年的一篇paper 引用:Lin M, Chen Q, Yan S. Network in network[J]. arXiv preprint arXiv ...

  6. 第三百七十七节,Django+Xadmin打造上线标准的在线教育平台—apps目录建立,以及数据表生成

    第三百七十七节,Django+Xadmin打造上线标准的在线教育平台—apps目录建立,以及数据表生成 apps目录建立 我们创建一个apps目录,将所有的app放到apps目录里去,这样方便管理,也 ...

  7. e867. 获取和设置外观

    To change the look and feel, you need to know the class name of the new look and feel. This example ...

  8. unity---Courtine 协程

    尊重他人的劳动,支持原创,转载请注明出处:http.dsqiu.iteye.com 记得去年6月份刚开始实习的时候,当时要我写网络层的结构,用到了协程,当时有点懵,完全不知道Unity协程的执行机制是 ...

  9. Keystone-all 命令

    本文档介绍Icehouse版keystone-all命令 keystone-all命令在一个进程中同时启动服务和管理API,为openstack提供服务目录,授权和身份认证服务. 用法 $ keyst ...

  10. CocoaPods:说点关于它的

    CocoaPods安装和使用教程 安装及使用方法,这里有现成的,很细致,不再赘述(发音:zhuìshù,敲半天ao'shu,找不到这个词 =.=)   记录一下遇到的问题 1.CocoaPods 版本 ...