【问题现象】
线上mysql数据库爆出一个慢查询,DBA观察发现,查询时服务器IO飙升,IO占用率达到100%, 执行时间长达7s左右。
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 ORDER BY g.modify_time DESC LIMIT 20 ;
【问题分析】
这条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字节的字符串,基本上都是为了显示信息,而不会用于查询条件, 因此表设计的时候,应该将这些列独立到另外一张表。
- SQL优化
如果表的设计已经确定,修改比较困难,那么也可以通过优化SQL语句来减少临时表的大小,以提升SQL执行效率。
常见的优化SQL语句方法如下:
1)拆分SQL语句
临时表主要是用于排序和分组,很多业务都是要求排序后再取出详细的分页数据,这种情况下可以将排序和取出详细数据拆分成不同的SQL,以降低排序或分组时临时表的大小,提升排序和分组的效率,我们的案例就是采用这种方法。
2)优化业务,去掉排序分组等操作
有时候业务其实并不需要排序或分组,仅仅是为了好看或者阅读方便而进行了排序,例如数据导出、数据查询等操作,这种情况下去掉排序和分组对业务也没有多大影响。
- 如何判断使用了临时表?
使用explain查看执行计划,Extra列看到Using temporary就意味着使用了临时表。
详细信息请参考MySQL官方手册: http://dev.mysql.com/doc/refman/5.1/en/internal-temporary-tables.html
转载: http://tech.uc.cn/?p=2218
相关推荐
oracle查找定位占用临时表空间较大的SQL语句方法,包括:(1)造成临时表空间暴涨的SQL还在运行中(2)造成临时表空间暴涨的SQL已经运行过了。
Oracle SQL语句性能优化是数据库管理中的关键环节,直接影响到系统的响应速度和资源利用效率。本文将详细探讨优化Oracle SQL语句的几个核心策略。 1. 选择合适的优化器 Oracle 提供了三种优化器:RULE(基于规则)...
以上34条优化建议涵盖了SQL语句的基础知识和优化技巧,通过实践和理解,能够有效提升SQL编程能力,让数据库性能达到最优。学习并掌握这些知识点,无论是对于初学者还是经验丰富的开发者,都是提高工作效率和解决问题...
总的来说,新一代智能SQL语句优化技术是数据库性能提升的一个重要突破,它通过自动化和智能化的方式,使得SQL优化变得更加高效和精确,从而帮助企业在日益复杂的数据库环境中保持竞争优势。随着技术的不断进步,我们...
在 SQL Server 中创建临时表可以使用以下语句: ```sql SqlCommand cm = new SqlCommand("create table #t(dc0 int)", conn); cm.ExecuteNonQuery(); ``` 但是,需要注意的是,执行完上述语句后,连接关闭,临时表将...
子查询可能会导致额外的扫描和临时表创建,优化子查询可能包括转换为连接操作或者使用存在性谓词。 8. **并行执行**: 对于大型数据集,数据库系统可能支持并行执行计划,通过多个处理器同时处理任务来加速查询。...
SQL语句优化是数据库性能优化中的一个核心环节,涉及对SQL查询语句的调整,以减少查询时间,提高系统资源利用率。 首先,要理解为什么需要优化SQL语句。随着数据库中数据量的不断增加,如果没有对SQL语句进行有效的...
SQL语句的优化是提升数据库系统性能的关键环节。在开发初期,由于数据量较小,可能无法明显察觉到SQL语句的性能差异,但随着数据的增长,优化SQL的重要性日益凸显。优化SQL不仅可以加快查询速度,还能有效减少系统...
2. 解决临时表空间不足问题的方法:通过编写记录使用临时表空间 SQL 语句的脚本,抓取最消耗临时表空间的语句,并对其进行优化。 3. AWR 报告的作用:AWR 报告可以显示占用临时表空间最高的 SQL 语句,但可能不准确...
11. **优化T-SQL编写**:编写高效的SQL语句,减少不必要的JOIN操作,避免子查询和嵌套循环,合理使用临时表和存储过程,以及使用合适的数据类型,都是提高SQL性能的重要手段。 综上所述,SQL语句优化是一个涉及多...
MySQL性能优化是数据库管理中的重要环节,特别是在处理大量数据时,高效的SQL语句能显著提升系统性能。以下是一些关于SQL语句性能优化的关键知识点: 1. **LIMIT使用**: LIMIT子句常用于限制查询返回的结果数量,...
4. **游标**:Oracle SQL支持游标,MySQL则不直接支持,需要使用存储过程或临时表来实现类似功能。 5. **函数和操作符**:两者内置的函数和操作符有所不同,例如Oracle的NVL对应MySQL的IFNULL,Oracle的TO_DATE对应...
总结,Oracle数据库SQL语句的性能优化是一个涉及多方面知识的综合过程,包括索引策略、查询优化器使用、子查询与连接优化、分页查询、存储过程设计、资源管理、SQL语句重构以及利用各种内置工具进行监控和调优。...
本文将围绕“SQL执行超长语句”这一主题进行深入探讨,包括超长语句可能出现的原因、如何编写更加高效合理的超长SQL语句以及如何优化执行性能等方面。 #### 一、超长SQL语句的定义与常见场景 ##### 定义 超长SQL...
《Effective MySQL之SQL语句最优化》是一本深入探讨如何提升数据库性能,特别是针对SQL查询进行优化的专业书籍。在数据库管理中,SQL语句的优化是至关重要的,它直接影响到系统的响应速度和整体效率。本篇文章将依据...
有时候,简单的调整,如使用JOIN替代子查询,就能带来显著的性能提升。 通过以上方法,我们可以根据SQL语句的执行计划来识别性能瓶颈,进而优化SQL,提高系统整体性能。实际操作中,需要结合具体数据库系统的特点和...
在Oracle数据库环境中,SQL语句性能优化是提升系统整体效能的关键环节。优化SQL不仅可以提高查询速度,还能增强用户体验,确保数据库系统的稳定运行。以下是一些关键的优化策略: 1. **合理使用索引**:索引是提升...