MySQL性能调优-SQL优化
概述
SQL优化是MySQL性能调优的关键环节,通过对SQL语句的优化可以显著提升数据库的查询性能。SQL优化主要关注三个方面:查询效率、资源使用和系统负载。本章将详细介绍各种实用的SQL优化技术和工具。
SQL优化基本原则
- 优先分析慢查询并优化高频率执行的SQL语句
- 充分利用索引来避免全表扫描
- 减少不必要的数据传输和计算
- 定期审查和维护执行计划的有效性
SQL性能分析工具
Performance Schema 和 Sys 模式的查询
Performance Schema 和 sys 模式是MySQL内置的性能分析工具集,它们提供了对数据库内部运行状态的洞察。
CALL sys.ps_truncate_all_tables(false); -- 清空 Performance Schema 表(保留结构)
以下是常用的性能分析查询:
-- 分析SQL执行历史记录 , 总时间最长的
SELECT * FROM sys.statement_analysis LIMIT 1\G;
-- 找出执行时间位于前5%的SQL语句
select * from sys.statements_with_runtimes_in_95th_percentile ;
-- 根据平均执行时间查看SQL
select * from performance_schema.events_statements_summary_by_digest order by avg_timer_wait desc limit 2\G;
-- 根据执行频次查看SQL
select * from performance_schema.events_statements_summary_by_digest order by count_star desc limit 2\G;
-- 按扫描行数降序查看SQL
select * from performance_schema.events_statements_summary_by_digest order by sum_rows_examined desc limit 2\G;
-- 按返回行数降序查看SQL
select * from performance_schema.events_statements_summary_by_digest order by sum_rows_sent desc limit 2\G;
性能诊断存储过程
MySQL sys 模式提供了多种便捷的存储过程帮助进行性能诊断:
存储过程进行性能监控
-- ps_trace_thread 存储过程用于跟踪指定线程的执行情况
CALL sys.ps_trace_thread(thread_id, 'output_file', 1, 10);
-- 参数说明:
-- thread_id: 需要跟踪的线程ID
-- 'output_file': 输出结果文件位置
-- 1: 监控时间间隔(秒)
-- 10: 采集次数
相关的性能监控功能
ps_trace_statement_digest: 跟踪指定SQL摘要的详细执行情况statement_performance_analyzer: 对比SQL执行的性能分析报告ps_statement_avg_latency_histogram: 生成SQL平均延迟分布直方图
索引优化分析
索引使用状况分析
-- 检查可能存在全表扫描的表
select * from sys.schema_tables_with_full_table_scans;
-- 检查疑似未使用的索引(注意:短期观察可能会误判常用索引未使用)
select * from sys.schema_unused_indexes ;
-- 检查可能存在冗余的索引
select * from sys.schema_redundant_indexes ;
不可见索引技术
MySQL 8.0+ 支持创建不可见索引(Invisible Indexes),这是进行性能回滚的有力手段。
- 功能:在不删除索引的情况下临时禁用
- 用途:测试索引删除的潜在影响,避免删除错误造成性能下降
- 特点:可随时恢复,无需经历创建索引的时间成本
索引设计优化技术
覆盖索引
覆盖索引是指索引中包含了查询所需的全部列,避免了访问数据页的过程,可极大提高查询性能。
-- 查看索引 'xxx' 由哪些列组成(按顺序),方便利用覆盖索引
SELECT COLUMN_NAME, SEQ_IN_INDEX
FROM information_schema.STATISTICS
WHERE INDEX_NAME = 'xxx'
ORDER BY SEQ_IN_INDEX
使用建议:
- 将SELECT语句中的字段包含在覆盖索引中
- 在多表JOIN查询中对连接字段建立联合覆盖索引
- 注意平衡覆盖字段的多少与索引大小的矛盾
延迟关联(Delayed Join)
对于大数据量的关联查询,延迟关联可以通过减少JOIN操作的数据量来提高性能。
-- 使用子查询缩小关联范围
SELECT * FROM table_a
WHERE id IN (
SELECT id FROM table_b
WHERE conditions_for_table_b
);
这种技术尤其是在分页查询中的应用非常有效:
- 先在小范围内完成过滤条件查询
- 然后进行表间关联
- 大幅减少关联过程中扫描的数据行数
多字段的联合索引设计
设计联合索引时,要考虑:
- 频繁一起查询的字段放在同一个索引中
- 根据区分度安排字段顺序(将选择性最高的字段放在前面)
- 遵守最左匹配原则:查询条件包含联合索引左侧的连续字段才可有效使用索引
索引创建最佳实践
- 等值匹配查询:字段区分度高的放前面
- 范围查询+其他条件:范围字段后面不放其他字段
- 包含NULL值的列:考虑是否允许NULL以及如何索引
锁相关信息查询
-- 检查当前数据锁状态(MySQL 5.7+ 和 8.0+)
select * from performance_schema.data_locks;
该查询可用于诊断死锁等问题,重点关注以下字段:
OBJECT_SCHEMA,OBJECT_NAME: 被锁对象LOCK_TYPE: 锁类型LOCK_MODE: 锁模式LOCK_STATUS: 锁状态
统计与优化策略
直方图统计
在特定的列上建立直方图。默认的统计信息存在于表和索引中,列中原本并没有。 直方图主要用于优化器进行更精确的查询计划选择,特别是在数据分布不均匀时。
直方图优势:
- 提供更好的选择度估计
- 改善数据倾斜表上的查询计划选择
- 减少估算误差
查看和整理表空间
检查磁盘可释放空间的查询:
select table_name,
round(data_length/1024/1024) as data_length_mb,
round(data_free/1024/1024) as data_free_mb
from information_schema.tables
where round(data_free/1024/1024) > 10
order by data_free_mb desc
limit 10;
对结果集较大或者长期未优化导致大量数据碎片的表进行空间整理:
-- 使用 OPTIMIZE TABLE 整理表碎片
OPTIMIZE TABLE your_table_name;
-- 或者使用 mysqlcheck 进行批量表空间整理
mysqlcheck -o database_name --all-databases
SQL编写和设计优化策略
避免全表扫描的技巧
- WHERE条件优化:始终将选择性高的条件放在前面
- LIKE优化:避免前置通配符(如
%keyword),应尽量使用后置通配符 - OR条件替换:使用UNION替换OR(当OR的字段都有索引时)
- 数值范围缩小:使用LIMIT提前终止搜索
JOIN优化技巧
- JOIN顺序:从小结果集开始JOIN
- 索引选择:确保连接字段上都有合适的索引
- 驱动表选择:通过EXPLAIN确认优化器选择正确的驱动表
排序优化
- 使用索引进行排序(ORDER BY子句字段与索引顺序一致)
- 尽可能使用单一索引满足排序需求
- 避免混合ASC和DESC排序(MySQL 8.0以前可能导致无法使用索引)
SQL执行计划分析(EXPLAIN)
理解执行计划的各个字段可以帮助我们更好地优化SQL:
-- 分析SQL执行计划
EXPLAIN FORMAT=JSON SELECT * FROM your_table WHERE conditions;
重点关注:
- type: 显示连接类型(最好到最差:system、const、eq_reg、ref、range、index、ALL)
- rows: MySQL估计需要遍历的行数
- Extra: 包含额外信息(Using Index, Using Where, etc.)
常见性能陷阱
- 隐式转换: 字段类型不匹配可能导致索引失效
- 函数包裹列: 在查询字段上使用函数(如
DATE(date_field))会使索引失效 - COUNT(*)与COUNT(字段): 不同情况选择不同的写法以获得更好性能
MySQL配置参数与SQL性能的关系
查询缓存(8.0已移除):
虽然MySQL 8.0移除了查询缓存,但在早期版本中需考虑其对特定工作负载的益处或负面影响。
临时表相关参数:
- tmp_table_size 和 max_heap_table_size:控制内存临时表的最大大小
- 影响需要临时表处理(如GROUP BY, ORDER BY)的SQL性能
排序和联接参数:
- sort_buffer_size:每个会话分配的排序缓冲区大小
- join_buffer_size:联接操作时使用的缓冲区大小
其他相关配置:
根据业务特点适当调整这些参数可以进一步提升SQL执行效率。
附注
MySQL的优化是一个综合性的过程,不仅包括SQL语句本身,也涉及系统参数调优、表结构设计、索引策略等多个方面,需要整体协调实施。