总结
- 获取慢查询SQL
- 已经执行完的SQL,检查慢查询日志,日志中有执行慢的SQL
- 正在执行中的SQL,show proccesslist;,结果中有执行慢的SQL
慢查询日志关键参数
| 名称 | 解释 | 
|---|---|
| Query_time | 查询消耗时间 | 
| Time | 慢查询发生时间 | 
- 分析慢查询SQL explain 慢SQL
explain关键参数
| 名称 | 解释 | 
|---|---|
| key | 实际用到的索引列 | 
| type | 索引类型 | 
| extra | 额外信息 | 
type部分值
| 名称 | 解释 | 
|---|---|
| consts | 基于主键或唯一索引查询,最多返回一条数据,优化阶段可得到数据 | 
| ref | 基于普通索引的等值查询,表间等值连接 | 
| range | 利用索引范围查询 | 
| index | 全索引扫描 | 
| ALL | 全表操作 | 
- 阿里java开发手册-泰山版,要求至少range
Extra部分值
| 名称 | 解释 | 
|---|---|
| Using index | 使用覆盖索引,减少表扫描和回表 | 
| Using index condition | 先条件过滤索引再查询数据 | 
| Using filesort | 使用外部排序,非索引排序 | 
| Using where | 使用where条件 | 
| Impossible where | where总是false | 
| Using temporary | 使用临时表,一般发生在order by无索引列时 | 
| Using join buffer (Block Nested Loop) | 在进行嵌套循环连接,内表大 | 
| Select tables optimized away | 该查询不需要访问实际的表,而是通过优化方式直接计算出结果 | 
- 优化慢SQL
准备数据库
库
CREATE DATABASE IF NOT EXISTS test_slow DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci;
use test_slow;
表
CREATE TABLE `person_info_large` (  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,  `code` VARCHAR (36),`name` VARCHAR (36),`title` VARCHAR (72),`location` VARCHAR (108),PRIMARY KEY `pk_id` (`id`),UNIQUE `uk_code` (`code`),KEY `idx_title_location`(`title`,`location`) 
) ENGINE = INNODB AUTO_INCREMENT = 1 DEFAULT CHARSET = utf8
行(java生成sql文件》导入sql文件)
package com.xcrj.gen;import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.UUID;public class Main {public static void main(String[] args) {generate(300 * 10000);}private static String rand36Str() {long time = System.currentTimeMillis();int random = (int) (Math.random() * Integer.MAX_VALUE);UUID uuid = new UUID(time, random);//随机种子return uuid.toString();}private static String rand36Str(int num) {StringBuilder sb = new StringBuilder();UUID uuid;for (int i = 0; i < num; i++) {uuid = UUID.randomUUID();sb.append(uuid.toString());}return sb.toString();}private static void generate(int size) {String row = "INSERT INTO researcher(`code`,`name`,`title`,`location`) VALUE(%s);";
//        System.out.println(String.format(sql,IdWorker.getId()));String path = "./test_slow_researcher.sql";File file = new File(path);if (!file.exists()) {try {file.createNewFile();} catch (IOException e) {e.printStackTrace();}}try (FileOutputStream fos = new FileOutputStream(path);BufferedOutputStream bos = new BufferedOutputStream(fos);) {for (int i = 0; i < size; i++) {StringBuilder sb = new StringBuilder();String code = rand36Str(1);String name = rand36Str(1);String title = rand36Str(2);String location = rand36Str(3);sb.append("'").append(code).append("'").append(",").append("'").append(name).append("'").append(",").append("'").append(title).append("'").append(",").append("'").append(location).append("'");bos.write(String.format(row, sb.toString()).getBytes());if (i < size - 1) {bos.write("\n".getBytes());}}} catch (IOException e) {e.printStackTrace();}}
}
开启慢查询日志
# 检查默认值
show variables like '%quer%';# 开启慢查询日志
set global slow_query_log=on;
# 设置慢查询阈值为1s
set global long_query_time=1;
# 查看慢查询日志路径
show global variables like 'slow_query_log_file'# 检查设置值,若发现未生效,关闭当前会话(关闭数据库)重新打开,再检查
show variables like '%quer%';

| 参数 | 含义 | 
|---|---|
| slow_query_log | 是否开启慢查询日志 | 
| slow_query_log_file | 慢查询日志路径 | 
| long_query_time | 慢查询阈值,默认10s | 
慢查询测试1,已经执行完的慢查询
# 统计
SELECT count(*) FROM researcher;
# 无索引列
SELECT `name` FROM researcher ORDER BY `name` DESC;
# 有索引列
SELECT `code` FROM researcher ORDER BY `code` DESC;
# 查询慢查询日志文件地址 /var/lib/mysql/333a2bf4a87e-slow.log
show variables like '%quer%';
# 查看慢查询日志
more /var/lib/mysql/333a2bf4a87e-slow.log
# 分析SQL
explain SELECT count(*) FROM researcher;
explain SELECT `name` FROM researcher ORDER BY `name` DESC;
explain SELECT `code` FROM researcher ORDER BY `code` DESC;
SELECT count(*) FROM researcher;
 
- Query_time: 大于18s
SELECT nameFROM researcher ORDER BYname DESC;
 
- Query_time: 大于19s
SELECT codeFROM researcher ORDER BYcode DESC;
 
- Query_time: 大于16s
explain SELECT count(*) FROM researcher;
 
- key=uk_code,可知count(*)会使用索引
- type=index
- extra=Using index
explain SELECT nameFROM researcher ORDER BYname DESC;
 
- key=NULL
- type=ALL
- extra=Using filesort
explain SELECT codeFROM researcher ORDER BYcode DESC;
 
- key=uk_code
- type=index
- extra=Using index
explain SELECT idFROM researcher ORDER BYid DESC;
 
- key=primary
- type=index
- extra=Using index
参数说明
慢查询日志部分参数
| 名称 | 解释 | 
|---|---|
| Query_time | 查询消耗时间 | 
| Time | 慢查询发生时间 | 
explain部分值
| 名称 | 解释 | 
|---|---|
| key | 实际用到的索引列 | 
| type | 索引类型 | 
| extra | 额外信息 | 
| select_type | 查询方式 | 
| possible_keys | 可能用到的索引列 | 
type部分值
| 名称 | 解释 | 
|---|---|
| consts | 基于主键或唯一索引查询,最多返回一条数据,优化阶段可得到数据 | 
| ref | 基于普通索引的等值查询,表间等值连接 | 
| range | 利用索引范围查询 | 
| index | 全索引扫描 | 
| ALL | 全表操作 | 
- 阿里java开发手册-泰山版,要求至少range
Extra部分值
| 名称 | 解释 | 
|---|---|
| Using index | 使用覆盖索引,减少表扫描和回表 | 
| Using index condition | 先条件过滤索引再查询数据 | 
| Using filesort | 使用外部排序,非索引排序 | 
| Using where | 使用where条件 | 
| Impossible where | where总是false | 
| Using temporary | 使用临时表,一般发生在order by无索引列时 | 
| Using join buffer (Block Nested Loop) | 在进行嵌套循环连接,内表大 | 
| Select tables optimized away | 该查询不需要访问实际的表,而是通过优化方式直接计算出结果 | 
select_type部分值
| 名称 | 解释 | 
|---|---|
| Simple | 简单查询 | 
| Primary | 关联查询或子查询的外层查询 | 
| Unoin | 关联查询或子查询的后续查询 | 
慢查询测试2,正在执行的慢查询
SELECT `name` FROM researcher ORDER BY `name` DESC;
show processlist;

- Time=34,已经执行了34s
恢复默认参数
# 检查默认值
show variables like '%quer%';
# 开启慢查询日志
set global slow_query_log=off;
# 设置慢查询阈值为1s
set global long_query_time=10;
# 检查设置值,若发现未生效,关闭当前会话(关闭数据库)重新打开,再检查
show variables like '%quer%';
# 重置表,包括自增ID
TRUNCATE TABLE researcher;