mysql由于临时表导致IO过高的性能优化过程分享(1)

使用explain查看执行计划,结果如下:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

这条sql语句的问题其实还是比较明显的: 查询了大量数据(包括数据条数、以及g.* ),然后使用临时表order by,但最终又只返回了20条数据。

DBA观察到的IO高,是因为sql语句生成了一个巨大的临时表,内存放不下,于是全部拷贝到磁盘,导致IO飙升。

【优化方案】

优化的总体思路是拆分sql,将排序操作和查询所有信息的操作分开。

第一条语句:查询符合条件的数据,只需要查询g.id即可

SELECT DISTINCT g.id FROM gm_game g

LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0

LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0

LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0

WHERE g.deleted = 0 ORDER BY g.modify_time DESC LIMIT 20 ;

第二条语句:查询符合条件的详细数据,将第一条sql的结果使用in操作拼接到第二条的sql

SELECT DISTINCT g.*, cp.name AS cp_name,c.name AS category_name,t.name AS type_name FROM gm_game g

LEFT JOIN gm_cp cp ON cp.id = g.cp_id AND cp.deleted = 0

LEFT JOIN gm_category c ON c.id = g.category_id AND c.deleted = 0

LEFT JOIN gm_type t ON t.id = g.type_id AND t.deleted = 0

WHERE g.deleted = 0 and g.id in(…………………) ORDER BY g.modify_time DESC ;

【实测效果】

在SATA机器上测试,优化前大约需要50s,优化后第一条0.3s,第二条0.1s,优化后执行速度是原来的100倍以上,IO从100%降到不到1%

在SSD机器上测试,优化前大约需要7s,优化后第一条0.3s,第二条0.1s,优化后执行速度是原来的10倍以上,IO从100%降到不到1%

可以看出,优化前磁盘io是性能瓶颈,SSD的速度要比SATA明显要快,优化后磁盘不再是瓶颈,SSD和SATA性能没有差别。

【理论分析】

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

临时表存储

MySQL临时表分为“内存临时表”和“磁盘临时表”,其中内存临时表使用MySQL的MEMORY存储引擎,磁盘临时表使用MySQL的MyISAM存储引擎;

一般情况下,MySQL会先创建内存临时表,但内存临时表超过配置指定的值后,MySQL会将内存临时表导出到磁盘临时表;

Linux平台上缺省是/tmp目录,/tmp目录小的系统要注意啦。

使用临时表的场景

  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字节的列;

临时表相关配置

tmp_table_size:指定系统创建的内存临时表最大大小; http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_tmp_table_size

max_heap_table_size: 指定用户创建的内存表的最大大小; http://dev.mysql.com/doc/refman/5.1/en/server-system-variables.html#sysvar_max_heap_table_size

注意:最终的系统创建的内存临时表大小是取上述两个配置值的最小值。

表的设计原则

使用临时表一般都意味着性能比较低,特别是使用磁盘临时表,性能更慢,因此我们在实际应用中应该尽量避免临时表的使用。 常见的避免临时表的方法有:

  1. 创建索引:在ORDER BY或者GROUP BY的列上创建索引;

  2. 分拆很长的列:一般情况下,TEXT、BLOB,大于512字节的字符串,基本上都是为了显示信息,而不会用于查询条件, 因此表设计的时候,应该将这些列独立到另外一张表。

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
发者,这些资料都将为你打开新的学习之门!**

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 对于MySQL磁盘IO高的问题,可以尝试以下几种方法来解决:1.优化SQL语句,减少查询时间;2.增加MySQL缓存,提升系统性能;3.更换更快的硬盘,提高磁盘IO速度;4.调整MySQL参数,显著提升系统性能;5.使用读写分离,把读写操作分离出来;6.使用可靠的集群系统,提高系统的扩展性和可用性;7.使用SSD来加速磁盘的读取和写入速度。 ### 回答2: MySQL磁盘IO高的问题主要是由于大量的磁盘读写操作导致的。以下是解决MySQL磁盘IO高的几种方法: 1. 优化查询语句:检查和优化查询语句,尽量减少不必要的磁盘读取。可以使用索引,避免全表扫描,以提高查询效率。 2. 调整MySQL缓存:增大MySQL的缓冲区以减少对磁盘的读写操作。可以适当调整参数innodb_buffer_pool_size和key_buffer_size。 3. 分散磁盘IO请求:将数据、日志和临时表等分别存储在不同的物理磁盘上,以减少磁盘IO的竞争。 4. 增加内存:提升系统的物理内存,增加系统缓存,减少对磁盘的读写操作。 5. 使用SSD硬盘:使用SSD(固态硬盘)替换传统的机械硬盘,SSD硬盘具有更高的读写速度,能够显著提升磁盘IO性能。 6. 合理分区:对大表进行分区,将数据分散存储在多个分区上,减轻单个分区的IO负载。 7. 减少不必要的索引:评估并删除不再使用的索引,避免更新索引时的额外IO开销。 8. 使用缓存技术:可以考虑使用缓存技术,如Redis,将频繁读取的数据缓存到内存中,减少磁盘IO操作。 以上是解决MySQL磁盘IO高的一些方法,具体措施可以根据实际情况进行调整,以达到减少磁盘IO的目的。同时,也可以通过监控工具不断优化,以保持系统的高性能和稳定性。 ### 回答3: MySQL磁盘I/O高的情况可能是由于以下几个原因导致的:缓存不足、查询语句不优化、磁盘性能低等。 首先,可以尝试优化数据库的缓存设置。MySQL有一个用于缓存数据和索引的缓冲池(InnoDB缓冲池)。可以通过增加缓冲池的大小来减少对磁盘的访问次数,提高系统性能。 其次,需要优化查询语句,避免不必要的全表扫描和重复查询。可以使用索引来加快查询速度,同时避免在查询语句中使用大量的JOIN和子查询等操作,优化查询逻辑。 此外,可以考虑使用更高速的磁盘设备。当磁盘性能较低时,可以通过升级为更高速的磁盘设备或使用RAID等技术来提升磁盘性能,减少I/O等待时间。 另外,还可以使用MySQL的分区表功能来将大表拆分成较小的分区,减少单个分区上的磁盘访问压力,提高磁盘IO性能。 最后,可以通过调整MySQL的参数来优化磁盘I/O性能。例如,可以调整innodb_flush_method参数来控制MySQL数据的写入方式,选择适合的方式来提高磁盘I/O性能。 需要根据具体情况分析和综合考虑以上解决方案,并逐步尝试和优化,以降低MySQL磁盘I/O的负载,提高系统性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值