MySQL调优

Posted 小李在成长

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL调优相关的知识,希望对你有一定的参考价值。

一、视图

1.1 视图的概念

​ 视图是基于一个表或多个表或视图的逻辑表,本身不包含数据,通过它可以对表里面的数据进行查询和修改。视图基于的表成为基表。视图是存储在数据字典里面的一条select语句。通过创建视图可以提取数据的逻辑上的集合或组合

1.2 视图的优点

1、对数据库的访问,因为视图可以有选择性的选取数据库里的一部分

2、可以把复杂的查询变得简单

3、维护数据的独立性,视图可以从多个表检索数据

4、对于相同的数据可以产生不同的视图

5、可以对权限进行控制

1.3 视图的创建

CREATE VIEW 视图名称 AS 子查询

如:创建一张基本工资大于2000元的员工信息视图

create 	view view2 as select * from emp where sal > 2000;

创建一张可以统计部门编号,部门名称,部门人数,部门平均工资的视图

create view ad view3 as select
	d.deptno,
	d.dname,
	count(e.deptno),
	IFNULL(round(avg(e.sal),2),0)
FROM
	emp e
right join dept d on (e.deptno = d.deptno)
GROUP BY
	e.deptno

1.4 视图的使用

查询视图语法:

SELECT * FROM 视图名称

SELECT * FROM  findAll

1.5 修改视图

语法:

create or replace view 视图名称 as 视图语句

或者

alterview 视图名称 as 查询语句

该语句用于更改已有视图的定义。其语法与CREATE VIEW类似。当视图不存在时创建,存在时进行修改

1.6 删除视图

如果一个视图不再使用时,可以直接通过DROP命令进行删除

drop view 视图名称

1.7 查看视图定义

语法:DESC 视图名称

二、索引

2.1 概念

索引是一种特殊的文件,它们包含着对数据表里所有记录的引用指针。数据库索引是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中的数据。索引的实现通常是使用B树以及变种B+树

​ 索引用来加快数据的检索,类似于书籍的索引。在数据库中索引可以减少数据库程序查询结果时需要读取的数据量,类似于在书籍中,我们利用索引可以不用翻阅整本书即可找到想要的内容。

2.2 索引的类型

主键索引:数据列不允许重复,不允许为NULL,一个表中只能有一个主键

唯一索引:数据列不允许重复,允许为NULL值,一个表中允许多个列创建唯一索引

单值索引:给表中的某一个字段添加索引

组合索引:给表中的多个字段添加索引,主要针对的是条件查询

注:还有一个全文索引,用的很少,这里就不做介绍

2.3 索引的创建

创建唯一索引

alter table 表名 add UNIQUE(列名)

创建单值索引

alter table 表名 add index 索引名称(列名)

组合索引

alter table 表名 add index 索引名称(列名1,列名2,...)

-- 给emp表中的sql字段添加索引
alter table emp add index sal_index(sal)

2.4 查询索引

查询某张表中已经存在的索引

语法:show index from 表名

2.5 删除索引

语法:alter table 表名 drep 索引名

-- 删除emp表中的sal_index索引
alter tabel emp drop index sal_index	

2.6 索引的优点和缺点

优点:

​ 可以大大加快数据的检索速度,这也是创建索引的最主要的原因

缺点

​ 时间方面:创建索引和维护索引需要耗费时间,具体的,当对表中的数据进行添加,删除,修改的时候,索引也是需要动态维护的,会降低增删改的执行效率

​ 空间方面:索引需要占用物理内存空间

2.7 索引的基本原理

​ 索引用来快速地寻找那些具有特定值的记录。如果没有索引,一般来说执行查询时遍历整张表。索引的原理很简单,就是把无序的数据变成有序的查询

1、把创建了索引的列的内容进行排序

2、对排序结果生成倒排表

3、在倒排表内容上拼上数据地址链

4、在查询的时候,先拿到倒排表内容,再取出数据地址链,从而拿到具体数据

2.8 创建数据的原则

给字段添加索引是为了提高查询效率,但不是所有的字段都可以添加索引,创建索引有以下特点。

​ 1、在经常需要搜索的列上,可以加快搜索的速度

​ 2、在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构

​ 3、在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;

​ 4、在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;

​ 5、更新频繁的字段不建议设置索引

​ 6、 尽量的扩展索引,不要新建索引。比如表中已经有a的索引,现在要加(a,b)的索引,那么只需要修改原来的索引即可。

​ 7、对于那些查询中很少涉及的列,重复值比较多的列不要建立索引

​ 8、对于定.义为text、image和bit的数据类型的列不要建立索引

试验代码

-- 查看表结构
DESC USER

-- 查询表中存在的索引
SHOW INDEX FROM USER

-- 给表中username添加唯一索引,字段本身是唯一的就适合添加唯一索引
ALTER TABLE USER ADD UNIQUE(username);

-- 给表中password添加单值索引,查询或者关联较多的字段适合添加单值索引
ALTER TABLE USER ADD INDEX password_index(PASSWORD)

-- 给表中添加多值索引,多个查询组合查询
ALTER TABLE USER ADD INDEX sex_age_index(sex,age)

-- 删除索引
ALTER TABLE USER DROP INDEX username
 
-- 创建触发器在user添加后备份到表user2中
CREATE TRIGGER user_tri 
AFTER 
INSERT ON USER 
FOR EACH ROW 
INSERT INTO user2(username) VALUES(new.username);

-- 测试触发器
INSERT INTO USER(username,PASSWORD,age,sex) VALUES(\'admin\',\'123\',18,1)

-- 查询触发器
SHOW TRIGGERS

-- 删除触发器
DROP TRIGGER user_tri

-- user数据修改后,user2同步修改,usre3将原来值进保存  这里mysql5.5还不支持
DELIMITER//
CREATE TRIGGER user_tri2
AFTER 
UPDATE ON USER
FOR EACH ROW
BEGIN
INSERT INTO user2(username,PASSWORD,age,sex) VALUES(new.username,new.password,new.age,new.sex);
INSERT INTO user3(username,PASSWORD,age,sex) VALUES(old.username,old.password,old.age,old.sex);
END//
DELIMITER

三、触发器

3.1 概念

​ 在MySQL里面也就是对某一个表的一定的操作,触发某种条件(Insert,Update,Delete 等)就会自定执行一些程序。和web中的监听器很像

3.2 触发器的创建

触发器语法:

create trigger 触发器名称
触发时机 
触发事件 on 表名 
for each row
触发器程序体

触发器解释:

​ 触发器名称:标识触发器名称,用户自行定义

​ 触发时机:可取值为BEFORE或者、UPDATE、DELETE

​ 触发事件:取值为INSERT、UPDATE或DELETE

​ 表名:标识建立触发器的表名,即是在那张表上建立的触发器

​ 触发器程序体:可以是一句SQL语句,或者用BEGIN和END包含多条语句

例如:现有两张表t1,t2,两张表中都有id,name字段,新加t1表记录后自动添加到t2中

create trigger trigger1
after
insert on t1
for each row
insert into t2(name) valus(new.name);
-- 说明:new值的是添加的新值,OLE指的是更新或者删除的旧值
-- INSERT只有NEW  UPDATE有NEW和OLD
-- DELETE只有OLD

注:一般情况下,Mysql默认是以;号作为结束执行语句。为了解决这个问题,可以用到delimiter语句。例如delimiter //,可以将结束符号变成//,创建完触发器后再执行delimiter ;将结束符号改回成;号

例如:

delimiter//
create trigger trigger2
after
update on t1
for each row
begin
insert into t2(name) value(new.name);
insert into t3(name) value(old,name);
end//
delimiter

3.3 查看触发器

语法:

show trigger

3.4 删除触发器

语法

drop trigger 触发器名称

四、储存过程(未完善)

4.1 概念

​ 存储过程是能完成一定操作的一组SQL语句,它在创建后以被有权用户在任何需要的地方调用。

​ 通过使用过程,不仅可以简化客户端应用程序的开发和维护,而且可以提高应用程序的运行性能。(假如某应用程序需要经常向某张表中插入数据,并且在插入数据时需要对数据进行检查验证,为了简化客户端的维护,可以使用存储过程)

4.2 创建储存过程

语法:

create procedure 储存过程名称
(
	[IN] 参数1参数类型,
	OUT参数2 参数类型
)
BEGIN
 程序代码块
END;

IN:代表输入参数(如果没有注明, 参数默认的类型为 in)

OUT:输出参数,不管有没有传值里面都是null

IN OUT;既可以做为输入参数,也可以做为输出参数

MySQL 存储过程名字后面的“()”是必须的,即使没有一个参数,也需要“()”

五、MySQL的结构体系

5.1 MySQL的核心配置文件查看位置

配置中的一些核心配置

[mysqld]

# socket=MYSQL

# The TCP/IP Port the MySQL Server will listen on
port=3306

# Path to installation directory. All paths are usually resolved relative to this.
# basedir="C:/Program Files/MySQL/MySQL Server 5.6/"

# Path to the database root
datadir=C:/ProgramData/MySQL/MySQL Server 5.6/Data

# The default character set that will be used when a new schema or table is
# created and no character set is defined
character-set-server=utf8

# The default storage engine that will be used when create new tables when
default-storage-engine=INNODB

5.2 MySQL的体系架构

组件说明:

1、MySQL向外提供的交互接口(Connectors)

2、连接池组件(Connection Pool)

3、管理服务组件和工具组件(Management Service & Utilities)

  • 主要负责数据的备份,数据库的集群,认证,权限,查询索引等

4、SQL接口组件(SQL Interface)

  • 负责接收SQL命令,判断SQL的类型是DML还是DDL还是视图等

5、查询分析组件(Parser)

  • 负责语法解析,就是我们的SQL语句,在这里进行语法的检查,语法检查失败直接返回语法错误。
  • 语义解析,比如查询的某张的表不存在直接返回xx表不存在。

6、优化器组件(Optimizer)

  • 对SQL命令进行优化,SQL的优化主要就是针对这块
  • MySQLServer会对发送过来的SQL语句进行优化,根据sql语句,生成一系列的执行计划,然后从执行计划选出最优的一条计划执行。
  • 在这里判断是否使用索引,如何使用索引

7、缓存文件(Caches & Buffers)

  • 查询缓存:主要对SQL语句缓存,把经常使用的SQL语句缓存起来
  • 数据缓存:从磁盘中加载数据到内容中,然后对内存中的数据进行过滤
  • 日志缓存:通过日志缓存恢复记录 这里就是undo和redo

8、插件式存储引擎(Pluggable Storage Engines)

9、物理文件(File System)

5.3 查询一条SQL语句的过程

MySQL的Query Profiler是一个使用非常方便的Query 诊断分析工具,通过该工具可以获取一条Query 在整个执行过程中多种资源的消耗情况,如 CPU,IO,IPC,SWAP 等,以及发生的 PAGE FAULTS,CONTEXT SWITCHE 等等,同时还能得到该 Query 执行过程中 MySQL 所调用的各个函数在源文件中的位置。

5.3.1 查看 profiling 参数
show variables like \'%profi%\';

profiling 默认是关闭的,所以需要手动开启

5.3.2 开启profiling

执行查询语句,每执行一次SQL语句都会生成一条profiling记录

select * from t_user where id = 2

查看所有sql的profiles

show profiles

查询单个sql的profiles

show profile cpu for query 6;

1.show profile默认是关闭的,并且开启后只存活于当前会话,也就说每次使用前都需要开启。

2.通过show profiles查看sql语句的耗时时间,然后通过show profile命令对耗时时间长的sql语句进行诊断。

3.注意show profile诊断结果中出现相关字段的含义,判断是否需要优化sql语句。

5.4 MySQL的储存结构

数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以 获得特定的功能。现在许多不同的数据库管理系统都支持多种不同的数据引擎。MySQL的核心就是存储引擎。

常用的存储引擎有以下:

  • Innodb引擎:Innodb引擎提供了对数据库ACID事务的支持。并且还提供了行级锁和外键的约束。它的设计的目标就是处理大数据容量的数据库系统。MySQL默认值的存储引擎。
  • MyIASM引擎:不提供事务的支持,也不支持行级锁和外键。

查询所有储存引擎

5.4.1 MyISAM与InnoDB对比
MyISAM Innodb
存储结构* 每张表被存放在三个文件:
frm-表结构定义、
MYD(MYData)-数据文件、
MYI(MYIndex)-索引文件
所有的表都保存在同一个数据文件中,
InnoDB表的大小只受限于操作系统文件的大小,
一般为2GB
存储空间* MyISAM可被压缩,存储空间较小 InnoDB的表需要更多的内存和存储,
它会在主内存中建立其专用的缓冲池用于高速缓冲数据和索引
文件格式 数据和索引是分别存储的,数据.MYD,索引.MYI 数据和索引是集中存储的,.ibd
记录存储顺序 按记录插入顺序保存 按主键大小有序插入
外键* 不支持 支持
事务* 不支持 支持
锁支持* 表级锁定 行级锁定、表级锁定,锁定力度小并发能力高
SELECT* MyISAM更优
INSERT、UPDATE、DELETE InnoDB更优
索引的实现方式 B+树索引,myisam 是堆表 B+树索引,Innodb 是索引组织表
哈希索引 不支持 支持
全文索引 支持 支持(MySQL5.6之前不支持)

总结:

Innodb(MySQL默认的):

  • 支持事务和外键
  • 磁盘的储存文件只有一个
  • 支持表和行的级锁

MyISAM:

  • 不支持事务和外键
  • 磁盘的储存文件有三个,占用磁盘空间少,会对文件进行压缩
  • 只支持表锁
5.4.2 引擎的选择

如果没有特别的需求,使用默认的Innodb即可。
MyISAM:查询效率高,储存空间小。
Innodb:更新(删除)操作频率也高,或者要保证数据的完整性;并发量高,支持事务和外键。。
实际业务中可以使用触发器来实现同步到两张表,写用Innodb,查询用MyISAM

七、数据库的SQL执行计划

7.1 EXPLAIN SQL执行计划

​ EXPLAIN命令是查看查询优化器如何决定执行查询的主要方法,使用EXPLAIN,只需要在查询中SELECT关键字之前增加EXPLAIN关键字即可,MySQL会在查询上设置一个标记,当执行查询时,这个标记会使其返回关于在执行计划中每一步的信息,而不是执行它,它会返回一行或者多行信息,显示出执行计划中的每一部分和执行的次序,从而可以从分析结果中找到查询语句或是表结构的性能瓶颈。

7.2 EXPLAIN的作用

1、分析出表的读取顺序

2、数据读取操作的操作类型

3、查看哪些索引可以使用

4、查看哪些索引在查询的时候被实际使用到

5、表之间的引用

6、查看每张表有多少行被优化器查询

7.3 EXPLAIN的使用

explain select * from t_user;

7.4 查询的结果参数含义

7.4.1 ID

每个select子句的标识id,代表执行select子句或操作表的顺序,id约大,越先执行,id相同,执行顺序由上至下

-- id约大,越先执行
EXPLAIN
select * from t_user u1 where u1.id =(
select u.id from t_user u where u.id = 2)

-- id相同,执行顺序由上至下
EXPLAIN
select * from t_user u1 where u1.id in(
select u.id from t_user u where u.id = 2)

-- id相同和不同,同时存在,遵从优先级高的优先执行,优先级相同的按照由上至下的顺序执行
EXPLAIN
select * from t_user u1,t_user u2 where u1.id =(
select u.id from t_user u where u.id = 2)

7.4.2 select_type(查询类型)

查询的类型,主要用于区别普通查询,联合查询,子查询等复杂查询

  • simple:简单的select查询,查询中不包含子查询或union查询
  • primary:查询中若包含任何复杂的子部分,最外层查询会被标记为primary
  • subquery:在select或where列表中包含了子查询
  • derived:在from列表中包含的子查询被标记为derived,mysql会递归将这些子查询,把结果放在一张临时表中
  • union:若第二个select出现在union之后,则被标记为union,若union包含在from子句的子查询中,外层select将被标记为derived
  • union result :union之后的结果集产生
-- 临时表
explain
select * from t_user u1,(select * from t_user u2) u3

-- UNION和UNION Result
explain
select * from t_user u1
UNION
select * from t_user u2

7.4.3 table(当前表名)

显示一行的数据时,关于到的表

7.4.5 type(当前表内访问方式)

查询的类型最好到最差的依次为:system > const > eq_ref > ref > index > All,一般情况下,得至少保证达到index级别的,最好是能达到ref级别,最高能达到const,system基本上是不能达到

  • system:表中有一行记录,这是const类型的特例,平时不会出现

  • const:表示通过索引一次就能找到了,const即常量,它用于比较primary key(主键)或者unique(唯一索引),因为只匹配一行数据,所以效率快,如果将主键置于where条件中,mysql就能将该查询转换成为一个常量

  • eq_ref:唯一性索引扫描,对于每个索引键,表中只能有一条记录与之匹配,常用于主键或唯一索引扫描

  • ref:非唯一性索引扫描,使用的是普通索引,返回匹配某个单独值的行,他可能会找到多个符合条件的行,所以他应该属于查询或扫描混合体

  • range:只检索给定范围的行,使用一个索引来选择行,如where语句中出现了between,<,>,in等查询,这种范围扫描索引比全表扫描要好,因为他只需要开始于索引的某一点,而结束于另一点,不用扫描全部索引。

  • index:扫描所有的索引,这通常比All快,因为索引文件通常比数据文件小,index是从索引中读取,All是从硬盘中读取数据

  • All:全表扫描,是最差的一种查询类型

-- const:主键索引扫描
explain
select empno from emp where empno = 7369;

-- eq_ref:唯一索引扫描(需要删除主键索引后才能看到效果)
alter table emp  add UNIQUE(ename); -- 添加唯一索引
explain
select ename,sal from emp where ename = \'ALLEN\';

-- ref:非唯一索引扫描
alter table emp  add index job_index(job); -- 添加普通索引
explain
select * from emp where job = \'SALESMAN\';

-- range:范围扫描
explain
select ename from emp where ename like \'al%\' -- 前面加%会导致索引失效

-- index: 扫描所有索引
explain
select empno from emp 

-- all:全表扫描
explain
select * from emp

7.4.6 possible_keys(可能使用到的索引)

显示可能应用在这张表中的索引,一个或多个,查询到的索引不一定是真正用到的索引

7.4.7 key(实际使用到的索引)

实际使用到的索引,如果为null,则表示没有使用索引,因此会出现possible_keys列可能有期望使用的索引,但是key为null,表示实际没有使用索引

7.4.8 key-length(使用到的索引长度)

表示索引中使用的字节数,而通过该列计算查询中使用的索引长度,在不损失精确性的情况下,长度越短越好,key_len表示的值为索引字段的可能长度

7.4.9 ref(引用到的上一个表的列)

显示索引的哪一列被使用了,如果可能的话是一个常数,哪些列或常量被用于查找索引所使用的字段

explain
select * from emp e,dept d where e.deptno = d.deptno

7.4.10 rows

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数

7.4.11 Extra(额外信息说明)

  • Using filesort:说明mysql会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取,mysql中无法利用索引完成的排序操作称为“文件排序”

  • Using temporary:使用了临时表保存中间结果,mysql在对查询结果排序时使用临时表,常见于order by 和分组查询group by

  • Using index:表示相应的select操作中使用了覆盖索引(Covering index),避免了访问表的数据行,效率不错。如果同时出现Using where,表名索引被用来执行索引键值的查找;如果没有同时出现Using where,表明索引用来读取数据而非执行查找动作。 其中的覆盖索引含义是所查询的列是和建立的索引字段和个数是一一对应的

  • Using where:表明使用了where过滤

  • Using join buffer:表明使用了连接缓存,如在查询的时候会有多次join,则可能会产生临时表

  • impossible where:表示where子句的值总是false,不能用来获取任何元祖。

  • select tables optimized away
    在没有GROUPBY子句的情况下,基于索引优化MIN/MAX操作或者对于MyISAM存储引擎优化COUNT(*)操作,不必等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。

  • distinct:优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作,即一旦MySQL找到了与行相联合匹配的行,就不再搜索了。

  • null:代表的没有使用索引,扫描的是全表。

-- Using index
explain
select empno from emp order by empno

-- Using filesort
explain
select * from emp order by sal

-- Using temporary;
explain
select comm from emp group by comm;

-- Using where
explain
select job from emp where job like \'a%\'
小结

type:访问类型,查看SQL到底是以何种类型访问数据的。
key:使用的索引,MySQL用了哪个索引,有时候MySQL用的索引不是最好的,需要force index()。
rows:最大扫描的列数。
extra:重要的额外信息,特别注意损耗性能的两个情况,using filesort和using temporary。

八、常见Mysql优化的手段

8.1 硬件层面

1.可以使用更大的内存,减少磁盘的IO

2.可以采用多核CPU,可以提高MySQL的执行速度

3.可以采用更好的磁盘来加快IO读写速度,如使用固态硬盘

8.2 软件层面

1.使用合适的储存引擎,当查询多的时候可以使用MyISAM储存引擎,当写多的时候可以使用InnoDB

8.3 建表

1.数据类型越小越好

​ 通常情况下,应该选择可以正确存储数据的最小数据类型,因为他们占用更小的磁盘、内存和CPU缓存,但是要确保没有低估需要存储值的范围,在Mysql中的多个地方增加数据类型范围是一件很痛苦的事情

2.使用简单的数据类型

​ 简单的数据类型的操作通常需要消耗更小的CPU资源,比如整型比字符串操作的代价更低

​ 如:Mysql中创建时间类型使用data类型或者time类型,而不使用varchar类型

3.尽量避免NULL

​ 通常情况下最好执行列为NOT NULL,除非真的需要存储NULL值。如果查询总包含可能为NULL的列,对MySQL来说更难优化,因为可为NULL的列使的索引、索引统计等都变的更加复杂。通常把字段设置为NOT NULL带来的性能提升比较小,但是如果计划在列上创建索引,就应该尽量避免设计成可为NULL的列

8.4 SQL的查询优化

一些高级的查询语句

show status;
show global status like "Com_select"; // 查询所有的
show status like \'Com_select\';//执行select操作的次数,一次会话
show status like \'Com_insert\';//执行insert操作的次数,注意,对于批量插入的操作,只算一次
show status like \'Com_update\';
show status like \'Com_delete\';

show status like \'Innodb_rows_read\' ;//select查询返回的行数
show status like \'Innodb_rows_inserted\' ;//执行insert操作插入的行数
show status like \'Innodb_rows_updated\' ;//执行update操作更新的行数
show status like \'Innodb_rows_deleted\' ;//执行delete操作删除的行数

SQL的机器读取顺序

分析:

从这个顺序中我们不难发现,所有的 查询语句都是从from开始执行的,
在执行过程中,每个步骤都会为下一个步骤生成一个虚拟表,这个虚拟表将作为下一个执行步骤的输入。

1)首先对from子句中的前两个表执行一个笛卡尔乘积,此时生成虚拟表 vt1(选择相对小的表做基础表)

2)接下来便是应用on筛选器,on 中的逻辑表达式将应用到 vt1 中的各个行,筛选出满足on逻辑表达式的行,生成虚拟表 vt2

3)如果是left outer join 就把左表在第二步中过滤的添加进来,如果是right outer join 那么就将右表在第二步中过滤掉的行添加进来,这样生成虚拟表 vt3

4)如果 from 子句中的表数目多余两个表,那么就将vt3和第三个表连接从而计算笛卡尔乘积,生成虚拟表,该过程就是一个重复1-3的步骤,最终得到一个新的虚拟表 vt3

5)应用where筛选器,对上一步生产的虚拟表引用where筛选器,生成虚拟表vt4

6)group by 子句将中的唯一的值组合成为一组,得到虚拟表vt5。注意:如果应用了group by,那么后面的所有步骤都只能得到的vt5的列或者是聚合函数(count、sum、avg等)

7)应用having筛选器,生成vt6。having筛选器是第一个也是为唯一一个应用到已分组数据的筛选器。

8)处理select子句。将vt6中的在select中出现的列筛选出来。生成vt7。

9)应用distinct子句,vt7中移除相同的行,生成vt8。事实上如果应用了group by子句那么distinct是多余的,

10)应用order by子句。按照order_by_condition排序vt8,此时返回的一个游标,而不是虚拟表。

11)应用limit子句,对结果集分页,生成虚拟表vt9

12)返回结果

8.4.1MySQL的慢查询日志
8.4.1 .1慢查询日志概念

MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阈值的语句,具体指运行时间超过long_query_time值的SQL,则会被记录到慢查询日志中。long_query_time的默认值为10,意思是运行10S以上的语句。默认情况下,Mysql数据库并不启动慢查询日志,需要我们手动来设置这个参数,当然,如果不是调优需要的话,一般不建议启动该参数,因为开启慢查询日志会或多或少带来一定的性能影响。慢查询日志支持将日志记录写入文件,也支持将日志记录写入数据库表。

8.4.1.2 慢查询日志的查询和开启

查看慢查询日志:
select @@slow_query_log;

开启:
SET GLOBAL slow_query_log=1;

8.4.1.3 查询慢查询次数
show status like \'slow_queries\';
8.4.1.4 设置查询的阈值

查看阈值:
show variables like \'long%\'

设置阈值:
set long_query_time=0.0001;

8.4.2 使用执行计划

采用执行计划

8.4.3 使用合适的索引

使用合适的索引

是指索引列不能是表达式的一部分,也不能是函数的参数。
应该养成简化where条件的习惯,始终将索引列单独放在运算符的一侧。

例如:
select * from ... where id + 1 = 5;
这是一个错误的用法,mysql无法解析id + 1 = 5 这个方程式,故不会使用到id列上的索引。>

8.4.3.1 使用前置索引

前缀索引是选择字符列的前n个字符作为索引,这样可以减少索引空间大小,降低重复的索引值,从而提高索引效率。
注意:MySQL无法使用前缀索引做ORDER BY 和GROUP BY

8.5 其他的操作优化

8.5.1 插入优化
-- 如
insert into t_table values(1,\'zs\',\'gg\'),(2,\'ls\',\'gg\');
8.5.2 删除优化

如果是删除一个百万级的数据表,那么建议可以先删除索引,删除完数据之后,再重新建立索引

8.5.3 表连接查询

MySQL采用的是驱动表的方式,所以如果是表关联查询,建议将小表作为主表,就是以小表来驱动大表

能用between的地方,就不要用in

8.6 库表结构优化

使用中间件Mycat进行读写分离等

使用分库分表

以上是关于MySQL调优的主要内容,如果未能解决你的问题,请参考以下文章

mysql进阶 with-as 性能调优

送书 | 解读MySQL性能调优“金字塔”

linux中怎么查看mysql数据库版本

mysql 与linux ~ 内存分析与调优

MYSQL数据库的设计与调优

Docker调优之mysql内存占用过大