数据库复习笔记12——MySQL数据库优化

MySQL数据库优化

一、优化SQL步骤(问题定位方法)

在应用程序开发过程中,由于初期数据量较少,开发人员写SQL语句更加注重功能上的实现,但是当应用系统正式上线之后,随着数据量急速增长,很多SQL语句开始逐渐显露出性能问题,对生产的影响也越来越大,此时这些有问题的SQL语句就成为整个系统性能的瓶颈,因此我们需要对它们进行优化。

当面对一个有SQL性能问题的数据库时,应该如何入手来进行系统的分析,使得能够尽快定位问题SQL并解决问题。

1、查看SQL执行频率

可以通过如下指令查看,在SQL数据库中,执行频率较高的是哪些操作(由此可以确定数据库是以查询为主,还是以插入为主),之后就可以进行有针对性的优化。

SHOW  STATUS  LIKE  "Comm_______";

SHOW  STATUS  LIKE  "Innodb_rows_%";

示例:

2、定位低效率执行SQL

可以通过以下两种方式定位执行效率较低的SQL语句。

  • 慢查询日志:通过慢查询日志可以定位那些执行效率较低的SQL语句。日志中包含所有执行时间超过long_query_time秒的SQL语句的日志文件。
  • show  processlist:慢查询日志在查询结束之后才会进行记录,所以在应用的执行效率出现问题的时候,慢查询日志并不能立刻定位到问题,这时候可以使用show  processlist命令查看当前数据库中正在进行的线程,包括线程的状态、是否锁表等,实时查看SQL的执行情况,同时对一些锁表操作进行优化。

3、explain分析执行计划

通过上述方法定位到效率较低的SQL语句之后,可以通过explain或者desc命令获取MySQL如何执行SELECT语句的信息,包括在SELECT语句执行过程中表如何连接和连接的顺序。

字段含义:

id:表示SQL语句执行过程中,表的读取顺序优先级,ID越大表示优先级越高。

select_type:表示查询过程中,SELECT的类型。如果单表查询就是SIMPLE。

table:表示的就是当前查询的数据来自哪张表。

type:表示的是访问类型,比如查询的时候用不用到索引。

possible_keys:表示可能应用在这张表的索引,一个或多个。

key:表示查询过程中实际使用的索引,如果为NULL,表示没有使用索引。

key_len:表示索引的长度(越短越好 )

rows:表示扫描的行数

extra:除前面展示的信息之外的一些额外信息。

4、show profile分析SQL

show profile可以帮助我们分析在查询过程中,各个阶段的耗时。

5、trace分析优化器执行计划

MySQL提供了对SQL的跟踪trace,通过trace文件能够进一步了解为什么优化器选择A计划,而不是选择B计划。

SQL Server中有一个优化器模块,是对我们客户端输入的SQL语句进行优化。

二、数据库优化

1、大批量插入数据

使用load命令通过本地文件导入数据的时候,如果导入的数据量极大(如百万级别的数据),有一些操作可以提高插入的效率。

(1)主键顺序插入

因为Innodb类型的表存储使用B+ Tree的数据结构,按照主键顺序进行保存,所以将导入的数据按照主键顺序进行排列,可以有效地提高导入数据的效率。如果Innodb表没有主键,那么系统会自动默认创建一个内部列作为主键,所以如果可以给表创建一个主键,将可以利用这点,来提高导入数据的效率。

(2)关闭唯一性校验

在导入数据前,执行SET  UNIQUE_CHECK = 0,关闭唯一性校验,在导入结束后执行 SET  UNIQUE_CHECK = 1,恢复唯一性校验,可以提高导入的效率。

(3)手动提交事务

如果应用使用自动提交的方式,建议在导入之前执行SET  AUTOCOMMIT= 0,关闭自动提交,导入结束之后,再执行SET  AUTOCOMMIT= 1,打开自动提交,也可以提高导入的效率。

2、优化INSERT语句

当进行数据的insert操作的时候,以下几种方式可以提高insert的效率:

(1)如果需要对一张表插入很多行数据,应该一次性进行插入,而不要写多条insert语句;这样将大大缩减客户端与数据库之前的连接、关闭等消耗。使得效率比分开执行的单个insert语句快。

示例,原始方式为:

insert  into  table   values(1, "ma", 24);

insert  into  table   values(2, "wang", 22);

insert  into  table   values(3, "liu", 23);

优化之后应该写为:

insert  into  table   values(1, "ma", 24), (2, "wang", 22), (3, "liu", 23);

(2)在事务中进行数据插入

关闭事务的自动提交,在事务中进行数据的插入。示例:

start   transaction;

insert  into  table   values(1, "ma", 24);

insert  into  table   values(2, "wang", 22);

insert  into  table   values(3, "liu", 23);

commit;

(3)数据有序插入

和上面介绍的load操作类似,在insert数据的时候,最好也按照数据的主键顺序进行insert。

3、优化Order By语句

MySQL数据库中Order By提供两种排序方式。

(1)第一种是通过对返回数据进行排序,也就是通常说的filesort排序,所有不是通过索引直接返回排序结果的排序都叫FilseSort排序。

(2)第二种通过有序索引顺序扫描直接返回有序数据,这种情况即为using index,不需要额外排序,操作效率高。

了解了MySQL的排序方式,优化目标就清晰了:尽量减少额外的排序,通过索引直接返回有序数据。where条件和Order By使用相同的索引,并且Order By的顺序和索引顺序相同,并且Order By的字段都是升序,或者都是降序。否则肯定需要额外的操作,这样就会出现FileSort。

4、优化Group By语句

由于Group  By实际上也同样会进行排序操作,而且与Order By相比,Group  By主要只是多了排序之后的分组操作。当然,如果分组的时候还使用了其他的一些聚合函数,那么还需要一些聚合函数的计算。所以,在Group  By的实现过程中,与Order By一样也可以利用索引。

如果查询包含group by,但是用户想要避免排序结果的消耗,则可以执行order by  null禁止排序。

示例如下:

select  age, count(*)  from emp  group  by  age  order  by  null;

对于group  by语句来讲,最优的优化方式还是对需要进行分组的字段建立索引。

5、优化嵌套查询

嵌套查询指的是:查询语句中,包含子查询语句。

例如:select  *  from  A  where  A.id   in   (select  B.id  from  B);

上述的查询方式较慢;对于嵌套查询的优化方式为:使用多表联查来代替嵌套查询。 

因此对于上面的查询语句,可以修改为如下内容:

select  *  from  A, B  where  A.id = B.id;

 6、优化OR条件

对于包含or的查询子句,如果要利用索引,则OR之间的每个条件列都必须用到索引,而且不能使用到复合索引(只能使用单列索引);如果没有索引,则应该考虑增加索引。

另外一个优化的方式是:使用UNION来替代OR。UNION就是并集的操作。

7、优化分页查询(优化limit语句)

一般分页查询时,通过创建覆盖索引能够比较好地提高性能。一个常见又非常头疼的问题就是 limit 2000000, 10  ,此时需要MySQL排序前2000010条记录,仅仅返回2000000 ——2000010的记录,其他记录丢弃,查询排序的代价非常大。

优化思路:

在索引上完成排序分页操作,最后根据主键关联回原表查询所需要的其他列内容。

三、数据库结构优化

  • 将字段很多的表分解成多个表。因为字段很多的表中存在一些使用频率低的字段,这些字段的存在就会大大影响访问速度;
  • 增加一些中间表。对于需要经常联合多个表进行查询时,可以建立一个中间表,将需要通过联合查询的数据插入到中间表,来提高效率;
  • 读写分离。在数据库并发大的情况下,最好的做法就是进行横向扩展,增加机器,以提升抗并发能力,而且还兼有数据备份功能。

四、应用程序优化

1、应用优化

上面的内容中,介绍了数据库的优化措施。但是在实际生产环境中,由于数据库本身的性能局限,就必须要对前台的应用进行一些优化,来降低数据库的访问压力。

1.1 使用连接池

对于访问数据库来说,建立连接的代价是比较昂贵的,因为我们频繁的创建关闭连接,是比较耗费资源的,我们有必要建立数据连接池,以提高访问的性能。

1.2 减少对MySQL的访问

(1)避免对数据进行重复检索

(2)增加缓存(cache)层。缓存层的实现方式有多种,例如使用文本方式存储,或者使用框架(Mybatis, Hibernate)提供的一级缓存/二级缓存,或者使用redis数据库来缓存数据。

(3)负载均衡。他的机制就是利用某种均衡算法,将固定的负载量分布到不同的服务器上,以此来降低单台服务器的负载,达到优化的目的。

2、Mysql中查询缓存优化

开启Mysql的查询缓存,当执行完全相同的SQL语句的时候,服务器就会直接从缓存中读取结果,当数据被修改,之前的缓存会失效,修改比较频繁的表不适合做查询缓存。

查询缓存的操作流程如下:

在MySQL8.0中已经删除了查询缓存。

3、Mysql内存管理及优化

内存优化原则:

(1)将尽量多的内存分配给Mysql做缓存,但要给操作系统和其他程序预留足够内存。

(2)MyISAM存储引擎的数据文件读取依赖于操作系统自身的IO缓存,因此,如果有MyISAM表,就要预留更多的内存给操作系统做IO缓存。

(3)排序区、连接区等缓存是分配给每个数据库会话(session)专用的,其默认值的设置要根据最大连接数合理分配,如果设置太大,不但浪费资源,而且在并发连接较高时会导致物理内存耗尽。

参考资料:

1、https://www.bilibili.com/video/BV1UQ4y1P7Xr?p=46

2、https://hillzhang1999.gitee.io/2020/05/29/shu-ju-ku-fu-xi-ji-yu-mysql/#toc-heading-127

猜你喜欢

转载自blog.csdn.net/ProQianXiao/article/details/108407984