MySQL SQL 优化命令行&问题 SQL 抓取方式
墨墨导读:优化的道路永无止境。
对于MySQL来说,可以说90%问题都在SQL语句上面。从问题SQL的筛选和优化,在MySQL环境下常用哪些方式。(以下版本是MySQL8.0.23)
MySQL优化前置知识基础
1. MySQL优化基础
RBO :
RBO所用的判断规则是一组内置的规则,这些规则是硬编码在数据库的编码中的,RBO会根据这些规则去从SQL诸多的路径中来选择一条作为执行计划
RBO最大问题在于硬编码在数据库里面的一系列固定规则,来决定执行计划。并没有考虑目标SQL中所涉及的对象的实际数量,实际数据的分布情况,这样一旦规则不适用于该SQL,那么很可能选出来的执行计划就不是最优执行计划。
CBO在会从目标诸多的执行路径中选择一个成本最小的执行路径来作为执行计划。这里的成本实际代表了MySQL根据相关统计信息计算出来目标SQL对应的步骤的IO,CPU等消耗。也就是意味着执行目标SQL所需要IO,CPU等资源的一个估计值。而成本值是根据索引,表,行的统计信息计算出来的。
通过SHOW INDEX结果中的列Cardinality来观察
2. MySQL索引特点:
打个比喻,主键就是所有数据的大脑,所有的操作必须通过大脑来获取。所以SQL语句里有效使用索引是重之又重的手段。
仅对二级索引获取结果是非常有效的,做到隔离的其他数据,但对于不在二级索引范围内的,就是回表操作,这部分需要谨慎考虑。
返回20%以上数据使用全表扫描数据; 数据集合小的表作为驱动表; 多个条件使用,组合索引; 索引键上不做运算;
MySQL优化命令行
1. EXPLAIN
EXPLAIN
EXPLAIN FORMAT=TREE
EXPLAIN FORMAT=JSON
EXPLAIN ANALYZE
EXPLAIN [options] FOR CONNECTION
EXPLAIN
MYSQL执行计划顺序普遍原则是:在所有组中,id值越大,优先级越高,越先执行,id如果相同,可以认为是一组,从上往下顺序执行
执行之前,要了解下显示字段代表意义:
EXPLAIN ANALYZE
MySQL 8.0.18引入了EXPLAIN ANALYZE,输出的信息是关于优化器估计执行成本和实际成本。
EXPLAIN ANALYZE可以用于SELECT语句,多表UPDATE和DELETE语句。备注:结果集显示里多了actual time。为了确认这个是否实际成本。通过status观察值,EXPLAIN ANALYZE之后 实际执行SELECT时 page是否也没变化。
EXPLAIN CONNECTION
EXPLAIN [options] FOR CONNECTION connection_id;
connection_id是连接标识符,从INFORMATION_SCHEMA PROCESSLIST表或SHOW PROCESSLIST语句获得.对于自己是connection id 无效。
##session1
mysql> SELECT CONNECTION_ID();
+-----------------+
| CONNECTION_ID() |
+-----------------+
| 14 |
+-----------------+
1 row in set (0.00 sec)
mysql> select * from employees;
#session2
mysql> EXPLAIN FOR CONNECTION 14;
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------+
| 1 | SIMPLE | employees | NULL | ALL | NULL | NULL | NULL | NULL | 299556 | 100.00 | NULL |
+----+-------------+-----------+------------+------+---------------+------+---------+------+--------+----------+-------+
备注:第一次执行有效,后面执行多次无效,目前来看不完善的功能,但很便利。
PROFILE语句显示当前会话过程中执行的语句的资源使用情况。
SHOW PROFILE [type [, type] ... ] [FOR QUERY n] [LIMIT row_count [OFFSET offset]] type: { ALL | BLOCK IO | CONTEXT SWITCHES | CPU | IPC | MEMORY | PAGE FAULTS | SOURCE | SWAPS }
ALL 显示所有性能信息 BLOCK IO 显示块IO操作的次数 CONTEXT SWITCHES 显示上下文切换次数,不管是主动还是被动 CPU 显示用户CPU时间、系统CPU时间 IPC 显示发送和接收的消息数量 MEMORY [当前没有实现] PAGE FAULTS 显示页错误数量 SOURCE 显示源码中的函数名称与位置 SWAPS 显示SWAP的次数
mysql> show variables like '%profiling%';
+------------------------+-------+
| Variable_name | Value |
+------------------------+-------+
| have_profiling | YES |
| profiling | OFF |
| profiling_history_size | 15 |
+------------------------+-------+
mysql> SET profiling = 1;
Query OK, 0 rows affected, 1 warning (0.00 sec)
mysql> SELECT * FROM employees WHERE first_name like 'Ho%' limit 5;
+--------+------------+------------+-----------+--------+------------+
| emp_no | birth_date | first_name | last_name | gender | hire_date |
+--------+------------+------------+-----------+--------+------------+
| 11105 | 1956-12-17 | Holgard | McAlpine | M | 1990-01-13 |
| 11484 | 1959-04-08 | Holgard | Siepmann | M | 1995-01-22 |
| 15162 | 1960-05-01 | Holgard | Koblitz | F | 1990-08-07 |
| 16372 | 1961-02-12 | Holgard | Terkki | M | 1991-06-08 |
| 16374 | 1963-05-23 | Holgard | Nergos | F | 1987-05-21 |
+--------+------------+------------+-----------+--------+------------+
5 rows in set (0.00 sec)
mysql> SHOW PROFILES;
+----------+------------+-------------------------------------------------------------+
| Query_ID | Duration | Query |
+----------+------------+-------------------------------------------------------------+
| 1 | 0.00568950 | SELECT * FROM employees WHERE first_name like 'Ho%' limit 5 |
+----------+------------+-------------------------------------------------------------+
1 row in set, 1 warning (0.00 sec)
mysql> SHOW PROFILE FOR QUERY 1;
+--------------------------------+----------+
| Status | Duration |
+--------------------------------+----------+
| starting | 0.004549 |
| Executing hook on transaction | 0.000030 |
| starting | 0.000016 |
| checking permissions | 0.000319 |
| Opening tables | 0.000055 |
| init | 0.000008 |
| System lock | 0.000009 |
| optimizing | 0.000011 |
| statistics | 0.000071 |
| preparing | 0.000205 |
| executing | 0.000357 |
| end | 0.000007 |
| query end | 0.000005 |
| waiting for handler commit | 0.000011 |
| closing tables | 0.000008 |
| freeing items | 0.000022 |
| cleaning up | 0.000010 |
+--------------------------------+----------+
17 rows in set, 1 warning (0.00 sec)
mysql> SHOW PROFILE CPU FOR QUERY 1;
备注:资源方面影响SQL语句执行效率的时候,可通过这个方式获取信息,特别是IO,CPU,网络等方面的问题,能有效的定位。
3. OPTIMIZER_TRACE
optimizer_trace:enabled:启用/禁用optimizer_trace功能 , one_line:决定了跟踪信息的存储方式,为on表示使用单行存储,否则以JSON树的标准展示形式存储。 optimizer_trace_features:该变量中存储了跟踪信息中可控的打印项,可以通过调整该变量,greedy_search,range_optimizerdynamic_range,repeated_subselect optimizer_trace_max_mem_size :optimizer_trace内存的大小,如果跟踪信息超过这个大小,信息将会被截断 optimizer_trace_offset:则是约束偏移量。和 LIMIT 一样,optimizer_trace_offset 从0开始计算
1.SET OPTIMIZER_TRACE="enabled=on";
2.执行 sql 语句
3. SELECT * FROM INFORMATION_SCHEMA.OPTIMIZER_TRACE limit 30 \G;
4.关闭 SET OPTIMIZER_TRACE="enabled=off";
备注:3个大步骤 ,9个子步骤把每个过程都列出来。
在主从架构下(所有条件相等下)碰到SQL执行得到不一样的执行时间,可通过这个方式查找原因。
必须真正的执行才能得到结果,所以合理使用:
EXPLAIN ANALYZE; PROFILE; OPTIMIZER_TRACE;
问题SQL语句抓取
慢日志; performance_schema系统性能表; 业务的一些反馈, 死锁检查,jdbc探针,网络流量镜像 等方式;
下面只普遍的前2种方式说明。
1. MySQL慢日志
开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能。
参数说明:
1)使用MySQL官方提供的开源工具mysqldumpslow进行分析
mysqldumpslow -t 10 /data/mysql/mysql-slow.log #显示出慢查询日志中最慢的10条sql
pt-query-digest /data/mysql/mysql-slow.log
备注:
第一部分:显示出了日志的时间范围,以及总的sql数量和不同的sql数量。
第二部分:显示出统计信息。
第三部分:每一个sql具体的分析
查询次数多且每次查询占用时间长的sql
通常为pt-query-digest分析的前几个查询IO消耗大的sql
注意pt-query-digest分析中的Rows examine项索引命中统计
注意pt-query-digest分析中Rows examine(扫描行数) 和 Rows sent (发送行数)的对比 ,如果扫描行数远远大于发送行数,则说明索引命中率并不高。
2. events_statements_summary_by_digest统计的SQL语句
events_statements_summary_by_digest:sql语句汇总统计数据,表结构说明如下:
备注:数据行数performance_schema_digests_size控制,默认是10000,如果超过这个最大值,新的sql语句无法插入。
崔虎龙:云和恩墨MySQL技术顾问,长期服务于金融、游戏、物流等行业的数据中心,设计数据存储架构,并熟悉数据中心运营管理的流程及规范,自动化运维等。擅长MySQL、Redis、MongoDB数据库高可用设计和运维故障处理、备份恢复、升级迁移、性能优化。自学通过了MySQL OCP 5.6和MySQL OCP 5.7认证。2年多开发经验,10年数据库运维工作经验,其中专职做MySQL工作8年;曾经担任过项目经理、数据库经理、数据仓库架构师、MySQL技术专家、DBA等职务;涉及行业:金融(银行、理财)、物流、游戏、医疗、重工业等。