MySQL学习(优化)

文章目录

统计信息

  • 查看当前会话SQL执行类型的统计信息
sql 复制代码
show session status like 'Com_______';
  • 查看全局(上次服务器启动至今)SQL执行类型的统计信息
sql 复制代码
show global status like 'Com_______';
  • 查看针对InnoDB的SQL执行类型的统计信息
sql 复制代码
show status like 'Innodb_rows_%';

定位低效率执行SQL

  • 慢查询日志(上一节)和show processlist
  • show processlist;
    id:当前执行的线程ID,可以使用函数connection_id()查看
    user:执行该语句的用户
    host:执行该语句的客户端IP和端口
    db:当前执行的数据库
    command:当前执行的命令状态,如sleep、query、connect等
    time:执行该语句所消耗的时间,单位秒
    state:当前SQL的执行状态
    info:当前执行的SQL语句,可以判断问题语句

explain分析执行计划

  • 可以获取SQL语句的执行信息,包括表如何连接和连接的顺序,SQL语句是否用到索引等
sql 复制代码
explain select * from emp a where a.empno=7369;
sql 复制代码
/*
    id:select查询的序列号,是一组数字,表示的是执行select子句或操作表的顺序
    select_type:表示查询的类型,SIMPLE(简单select,不使用union或子查询)、PRIMARY(主查询,最外层的select)、
                UNION(UNION中的第二个或后面的SELECT语句)、SUBQUERY(子查询中的第一个SELECT)等
    table:表示查询涉及的表或衍生表
    type:表示表的连接类型,性能由好到差的连接类型为system、const、eq_reg、ref、range、index和all
    possible_keys:表示查询可能使用到的索引
    key:表示实际使用的索引
    key_len:索引的长度
    ref:表之间的引用,即哪些列或常量被用于和前表进行连接
    rows:扫描的行数,估算的值
    filtered:按表条件过滤的行数的百分比
    extra:额外的信息
        Using filesort:说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取
        Using temporary:使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表,比如分组
        Using index:SQL所需要返回的所有列数据都在一棵索引树上,避免访问表的数据行,比如按照索引列分组
        Using where:在查找使用索引的情况下,需要回表去查询所需数据
        Using index condition:查找使用索引,但是需要回表查询数据
        Using index,Using where :在查找使用索引的情况下,不需要回表查询数据
*/

id

sql 复制代码
-- id相同时,执行顺序由上至下
    explain select * from emp a,dept b where a.empno=7369 and a.deptno=b.deptno;
-- id不同,如果是子查询,id的序号会递增,id值越大优先级越高,越先被执行
    explain select * from dept b where b.deptno = (select a.deptno from emp a where a.empno=7839);

select_type

sql 复制代码
-- SIMPLE:简单select,不使用UNION或子查询等
explain select * from emp;  -- SIMPLE
explain select * from emp a, dept b where a.deptno=b.deptno;    -- SIMPLE
-- PRIMARY:主查询,子查询最外层查询控制
-- SUBQUERY:子查询内层第一个select语句
explain select * from dept b where b.deptno = (select a.deptno from emp a where a.empno=7839);    -- PRIMARY和SUBQUERY
-- DERIVED:派生表,from子句中的子查询
explain select * from (select * from emp limit 2) a;    -- DERIVED
-- UNION:UNION语句中第二个select开始
-- UNION RESULT:从union结果集获取结果的select
explain select * from emp a where a.empno=7369 union select * from emp b where b.empno=7839;    -- UNION和UNION RESULT

type

sql 复制代码
 explain select * from emp;  -- ALL:全表扫描
 -- NULL:不访问任何表和索引直接返回结果
 explain select now();
 -- system:查询系统表,直接从内存读取数据,不会从磁盘读取数据,5.7版本之后不显示system而是all
 explain select * from mysql.user;
 -- const:通过索引一次就找到,用于主键或唯一索引扫描
 explain select * from emp a where a.empno=7369;
 -- eq_ref:左表有主键约束,且与右表的数据一一对应,右表查询时,左表的type是eq_ref
     -- 创建符合要求的表
         create table user1(id int, name varchar(20));
         insert into user1 values(1, '张三'), (2, '李四'), (3, '王五');
         create table user2(id int, age int);
         insert into user2 values(1, 30), (2, 40), (3, 50);
     -- 无主键时执行查询
         explain select * from user1 a,user2 b where a.id=b.id;  -- all,all
     -- 给user1表添加主键时执行查询
         alter table user1 add primary key(id);
         explain select * from user1 a,user2 b where a.id=b.id;  -- eq_ref,all
 -- ref:非唯一索引扫描,返回匹配某个单独值的所有行
     -- 删除user1表的primary key
         alter table user1 drop primary key;
     -- 添加普通索引
         create index idx_id on user1(id);
     -- 执行查询
         explain select * from user1 a,user2 b where a.id=b.id;  -- ref,all
 -- range:索引范围扫描,对索引列执行范围查询
     explain select * from emp a where a.empno between 7369 and 7839;    -- range
 -- index:索引全表扫描,把索引从头到尾扫一遍
     explain select a.empno from emp a;  -- index

show profiles分析

sql 复制代码
-- 查看是否支持profile
    select @@have_profiling;
-- 开启profile
    set profiling=1;
-- 执行SQL
    show databases;
    use test1;
    show tables;
    select count(*) from emp;
-- 查看profile
    show profiles;
-- 查看profile详情
    show profile for query 44;
-- 查看cpu情况(可选all 所有,block io 块io,context switch 上下文切换,page faults 页面错误)
    show profile cpu for query 67;

trace分析优化器执行计划

sql 复制代码
-- 开启trace,设置格式为json,并设置trace最大可使用的内存大小
set optimizer_trace="enabled=on", end_markers_in_json=on, optimizer_trace_max_mem_size=1000000;

select * from emp a, dept b where a.deptno=b.deptno;
-- 查看trace
select * from information_schema.optimizer_trace \G;    -- 这条语句要在cmd中运行

避免索引失效

sql 复制代码
/*
   1. 组合查询最左原则
   2. 范围查询右边的索引失效
   3. 不要在索引列上使用函数或运算
   4. 字符串不加单引号索引失效
   5. 尽量避免select *,用具体字段代替
   6. or分隔的条件,or条件列索引失效
   7. %开头的like索引失效(弥补不足,不要select *,使用索引列代替)
   8. 如果索引比全表扫描更慢,索引失效
   9. is null和is not null当数据null少时is not null失效,当数据null多时is null失效
   10. 当主键索引时,in和not in都有效,当为普通索引时,in有效,not in失效
   11. 尽量使用复合索引,因为单列索引最多只会生效一个最优的
*/

SQL优化

从本地导入数据

sql 复制代码
show global variables like 'local_infile';  -- 查看是否开启允许从本地导入数据
set global local_infile=1;  -- 开启允许从本地导入数据
sql 复制代码
-- load data local infile '本地数据文件路径' into table 表名 fields terminated by ',' lines terminated by '\n';
-- fields 指定字段分割符,lines 指定行分隔符

-- 数据最好让主键有序,这样导入更快
-- 关闭唯一性校验
   set unique_checks=0;

优化insert语句

sql 复制代码
/*
    1. 不要多次使用insert into,在一条insert into 中插入多条数据,如insert into values(),()...
    2. 在手动事务中进行数据插入
    3. 数据有序插入
*/

优化order by语句

sql 复制代码
create index idx_name_sal on emp(sal, ename);
drop index idx_name_sal on emp;
explain select * from emp a order by a.sal;     -- Using filesort
explain select a.empno from emp a order by a.sal;    -- Using index
-- order by 后面多个排序字段尽量排序方式相同
explain select a.empno from emp a order by a.sal desc, a.ename;     -- Using index & Using filesort
explain select a.empno from emp a order by a.sal, a.ename;    -- Using index
-- order by 后面多个排序字段尽量与组合索引顺序一致
explain select a.empno from emp a order by a.ename, a.sal;    -- Using index & Using filesort

优化filesort

sql 复制代码
show variables like 'max_length_for_sort_data'; -- 4096
show variables like 'sort_buffer_size'; -- 262144
-- 增大这两个值,使得程序优选一次扫描算法,占用内存开销,提高排序效率

优化子查询: 将子查询优化为join

sql 复制代码
explain select * from emp a where a.deptno in (select b.deptno from dept b);
explain select * from emp a join dept b on a.deptno=b.deptno;

优化limit查询

sql 复制代码
-- 如果查询从第100万条数据向后10条数据,需要对100万加10条数据排序,但只取10条数据,代价过大
-- 1. 在索引上完成排序分页操作,最后根据主键关联回原表查询所需的其他列
-- 2. 主键自增的表,比如id 直接大于100万,再limit 10
相关推荐
南城花随雪。5 分钟前
硬盘(HDD)与固态硬盘(SSD)详细解读
数据库
儿时可乖了6 分钟前
使用 Java 操作 SQLite 数据库
java·数据库·sqlite
懒是一种态度7 分钟前
Golang 调用 mongodb 的函数
数据库·mongodb·golang
天海华兮10 分钟前
mysql 去重 补全 取出重复 变量 函数 和存储过程
数据库·mysql
CV学术叫叫兽35 分钟前
一站式学习:害虫识别与分类图像分割
学习·分类·数据挖掘
我们的五年1 小时前
【Linux课程学习】:进程程序替换,execl,execv,execlp,execvp,execve,execle,execvpe函数
linux·c++·学习
gma9991 小时前
Etcd 框架
数据库·etcd
爱吃青椒不爱吃西红柿‍️1 小时前
华为ASP与CSP是什么?
服务器·前端·数据库
一棵开花的树,枝芽无限靠近你1 小时前
【PPTist】添加PPT模版
前端·学习·编辑器·html
VertexGeek1 小时前
Rust学习(八):异常处理和宏编程:
学习·算法·rust