后端接口性能优化分析-数据库优化(上)

简介: 后端接口性能优化分析-数据库优化

常见思路


15.数据库优化


索引


提到接口优化,相信最直接的就是会想到添加索引。没错,添加索引就是成本最小的优化,而且一般优化效果都很不错。


索引优化这块的话,一般从这几个维度去思考:


  • 你的SQL加索引了没?
  • 你的索引是否真的生效?
  • 你的索引建立是否合理?


SQL没加索引


我们开发的时候,容易疏忽而忘记给SQL添加索引。所以我们在写完SQL的时候,就顺手查看一下 explain执行计划。

explain select * from user_info where userId like '%123';

你也可以通过命令show create table ,整张表的索引情况。

show create table user_info;

如果某个表忘记添加某个索引,可以通过alter table add index命令添加索引

alter table user_info add index idx_name (name);

一般就是:SQLwhere条件的字段,或者是order by 、group by后面的字段需需要添加索引。


索引不生效


查看索引使用情况


在sql前面加上explain关键字,就能够看到它的执行计划,通过执行计划,我们可以清楚的看到表和索引执行的情况,索引有没有执行、索引执行顺序和索引的类型等。


explain详解


用一条简单的sql看看使用explain关键字的效果:

explain select * from test1;

id列


该列的值是select查询中的序号,比如:1、2、3、4等,它决定了表的执行顺序。


某条sql的执行计划中一般会出现三种情况:


  • id相同
  • id不同
  • id相同和不同都有 那么这三种情况表的执行顺序是怎么样的呢?


id相同:


执行sql如下:

explain select * from test1 t1 inner join test1 t2 on t1.id=t2.id

结果:

图中我们看到执行结果中的两条数据id都是1,是相同的。


这种情况表的执行顺序是怎么样的呢?


答案:从上到下执行,先执行表t1,再执行表t2。


id不同:


执行sql如下:

explain select * from test1 t1 where t1.id = (select id from  test1 t2 where  t2.id=2);

结果:

我们看到执行结果中两条数据的id不同,第一条数据是1,第二条数据是2。


这种情况表的执行顺序是怎么样的呢?


答案:序号大的先执行,这里会从下到上执行,先执行表t2,再执行表t1。


id相同和不同都有:


执行sql如下:

explain
select t1.* from test1 t1
inner join (select max(id) mid from test1 group by id) t2
on t1.id=t2.mid

结果:

我们看到执行结果中三条数据,前面两条数据的的id相同,第三条数据的id跟前面的不同。


这种情况表的执行顺序又是怎么样的呢?


答案:先执行序号大的,先从下而上执行。遇到序号相同时,再从上而下执行。所以这个列子中表的顺序顺序是:test1、t1


select_type列


常用的其实就是下面几个:

下面看看这些SELECT类型具体是怎么出现的:


SIMPLE


执行sql如下:

explain select * from test1;

结果:

它只在简单SELECT查询中出现,不包含子查询和UNION,这种类型比较直观就不多说了。


PRIMARY 和 SUBQUERY

explain select * from test1 t1 where t1.id = (select id from  test1 t2 where  t2.id=2);

结果:

我们看到这条嵌套查询的sql中,最外层的t1表是PRIMARY类型,而最里面的子查询t2表是SUBQUERY类型。


DERIVED


执行sql如下:

explain
select t1.* from test1 t1
inner join (select max(id) mid from test1 group by id) t2
on t1.id=t2.mid

结果:

最后一条记录就是衍生表,它一般是FROM列表中包含的子查询,这里是sql中的分组子查询。


UNION 和 UNION RESULT


执行sql如下:

explain
select * from test1
union
select* from test2

结果:

test2表是UNION关键字之后的查询,所以被标记为UNION,test1是最主要的表,被标记为PRIMARY。而表示id=1和id=2的表union,其结果被标记为UNION RESULT。


UNION 和 UNION RESULT一般会成对出现。


此外,回答上面的问题:id列的值允许为空吗?


如果仔细看上面那张图,会发现id列是可以允许为空的,并且是在SELECT类型为: UNION RESULT的时候。


table列


该列的值表示输出行所引用的表的名称,比如前面的:test1、test2等。


但也可以是以下值之一:


:具有和id值的行的M并集N。 :用于与该行的派生表结果id的值N。派生表可能来自(例如)FROM子句中的子查询 。 :子查询的结果,其id值为N


partitions列


该列的值表示查询将从中匹配记录的分区


type列


该列的值表示连接类型,是查看索引执行情况的一个重要指标。


执行结果从最好到最坏的的顺序是从上到下。


我们需要重点掌握的是下面几种类型:

system > const > eq_ref > ref > range > index > ALL


在演示之前,先说明一下test2表中只有一条数据:

并且code字段上面建了一个普通索引:

下面逐一看看常见的几个连接类型是怎么出现的:


system


这种类型要求数据库表中只有一条数据,是const类型的一个特例,一般情况下是不会出现的。


const


通过一次索引就能找到数据,一般用于主键或唯一索引作为条件的查询sql中,执行sql如下:

explain select * from test2 where id=1;

结果:

eq_ref


常用于主键或唯一索引扫描。执行sql如下:

explain select * from test2 t1 inner join test2 t2 on t1.id=t2.id;

结果:

此时,有人可能感到不解,const和eq_ref都是对主键或唯一索引的扫描,有什么区别?

答:const只索引一次,而eq_ref主键和主键匹配,由于表中有多条数据,一般情况下要索引多次,才能全部匹配上。


ref


常用于非主键和唯一索引扫描。执行sql如下:

explain select * from test2 where code = '001';

结果:

range


常用于范围查询,比如:between … and 或 In 等操作,执行sql如下:

explain select * from test2 where id between 1 and 2;

结果:

index


全索引扫描。执行sql如下:

explain select code from test2;

结果:

ALL


全表扫描。执行sql如下:

explain select *  from test2;

结果:


possible_keys列

explain select * from test1 t1 where t1.id = (select id from  test1 t2 where  t2.id=2);

该列表示可能的索引选择。


key列


该列表示实际用到的索引。


可能会出现possible_keys列为NULL,但是key不为NULL的情况。


演示之前,先看看test1表结构:

test1表中数据:

使用的索引:

code和name字段使用了联合索引。

explain select code  from test1;

结果:

这条sql预计没有使用索引,但是实际上使用了全索引扫描方式的索引。


key_len列


该列表示使用索引的长度。上面的key列可以看出有没有使用索引,key_len列则可以更进一步看出索引使用是否充分。不出意外的话,它是最重要的列。

有个关键的问题浮出水面:key_len是如何计算的?


决定key_len值的三个因素:


  1. 字符集
  2. 长度
  3. 是否为空


常用的字符编码占用字节数量如下:

目前我的数据库字符编码格式用的:UTF8占3个字节。


mysql常用字段占用字节数:

此外,如果字段类型允许为空则加1个字节。


上图中的 184是怎么算的?


184 = 30 * 3 + 2 + 30 * 3 + 2


再把test1表的code字段类型改成char,并且改成允许为空:

执行sql如下:

explain select code  from test1;

结果:

怎么算的? 183 = 30 * 3 + 1 + 30 * 3 + 2


还有一个问题:为什么这列表示索引使用是否充分呢,还有使用不充分的情况?


执行sql如下:

explain select code  from test1 where code='001';

结果:

上图中使用了联合索引:idx_code_name,如果索引全匹配key_len应该是183,但实际上却是92,这就说明没有使用所有的索引,索引使用不充分。


当"EXPLAIN"语句中的"key_len"显示使用索引不充分时,意味着查询在执行时没有充分利用表的索引,可能会导致以下后果:


  • 查询性能下降:由于没有充分利用索引,查询执行时需要扫描更多的数据行,因此查询的性能可能会降低。(查询性能下降:索引的主要作用是加速查询操作,当查询没有充分利用索引时,数据库需要扫描更多的数据行来获取所需的数据。这将导致查询的执行时间增加,性能下降。对于复杂的查询或者大数据量的表来说,性能下降可能会非常明显。在极端情况下,如果查询始终无法充分利用索引,可能会导致系统陷入繁忙状态,无法及时响应其他查询和事务。)
  • 系统资源浪费:当查询没有充分利用索引时,可能会导致更多的系统资源被占用,如CPU、内存和磁盘I/O等,从而影响其他查询和事务的执行。(系统资源浪费:当查询没有充分利用索引时,数据库可能需要使用更多的系统资源来完成查询操作。这可能导致CPU、内存和磁盘I/O等资源的使用率上升,从而影响其他查询和事务的执行。例如,如果CPU使用率过高,可能会导致其他查询和事务的执行被阻塞,从而降低系统的并发处理能力。同样,如果内存使用率过高,可能会引发内存泄漏或者OOM(内存溢出)等异常。)
  • 增加数据库负载:如果长时间存在索引不充分的情况,可能会导致数据库的负载增加,进一步影响数据库的稳定性和可用性。(增加数据库负载:如果长时间存在索引不充分的情况,可能会导致数据库的负载增加。在高负载的情况下,数据库可能需要处理更多的查询和事务,从而影响数据库的稳定性和可用性。此外,高负载还可能导致数据库的响应时间变长,进一步影响用户体验和业务处理速度。在极端情况下,过高的负载可能会导致数据库崩溃,从而导致数据丢失和系统崩溃。)
  • 影响业务处理:由于查询性能下降,可能会导致业务处理速度变慢,影响用户体验,甚至可能导致业务系统崩溃。因此,当"EXPLAIN"语句中的"key_len"显示使用索引不充分时,应尽快采取措施优化查询和索引,以提高查询性能、降低系统资源消耗,并保障数据库的稳定性和可用性。(影响业务处理:由于查询性能下降,可能会导致业务处理速度变慢,影响用户体验。例如,在电子商务网站上,如果商品搜索查询的性能下降,可能会导致用户无法快速找到所需的商品,从而降低购物体验。在某些情况下,如果查询性能下降严重,可能会导致业务系统崩溃,从而导致数据丢失和系统崩溃。因此,对于关键业务系统来说,确保查询充分利用索引非常重要。)


ref列


该列表示索引命中的列或者常量。


执行sql如下:

explain select *  from test1 t1 inner join test1 t2 on t1.id=t2.id where t1.code='001';

结果:

我们看到表t1命中的索引是const(常量),而t2命中的索引是列sue库的t1表的id字段。


rows列


该列表示MySQL认为执行查询必须检查的行数。


对于InnoDB表,此数字是估计值,可能并不总是准确的。


Extra列


该字段包含有关MySQL如何解析查询的其他信息,这列还是挺重要的,但是里面包含的值太多,就不一一介绍了,只列举几个常见的。


Impossible WHERE


表示WHERE后面的条件一直都是false

explain select code  from test1 where 'a' = 'b';

Using filesort


表示按文件排序,一般是在指定的排序和索引排序不一致的情况才会出现。

explain select code  from test1 order by name desc; 

这里建立的是code和name的联合索引,顺序是code在前,name在后,这里直接按name降序,跟之前联合索引的顺序不一样。


Using index


表示是否用了覆盖索引,说白了它表示是否所有获取的列都走了索引。


Using temporary


表示是否使用了临时表,一般多见于order by 和 group by语句。

explain select name  from test1 group by name;

Using where


表示使用了where条件过滤。


索引优化的过程


先用慢查询日志定位具体需要优化的sql


使用explain执行计划查看索引使用情况


重点关注:


  • key(查看有没有使用索引)
  • key_len(查看索引使用是否充分)
  • type(查看索引类型)
  • Extra(查看附加信息:排序、临时表、where条件为false等)


一般情况下根据这4列就能找到索引问题。


以一个慢sql工单举例,大概是这样的 “select xxx from tabel where type = 1”。


咦,type字段明明有索引啊,为啥是慢sql呢?


通过执行explain,发现实际上数据库执行了全表扫描,从而被系统判定为慢sql。所以这就要分析有索引的情况,索引为什么失效了。


不满足最左匹配


假如表中有个组合索引,idx_start_org_code_start_province_id_trans_type,它的索引顺序如下:


start_org_code,

start_province_id,

trans_type


当我们从第二个索引字段开始查询时就不会走索引:

因为不满足索引的 最左匹配原则,该原则只适用于 1 12 123 这种查询情况。


后端接口性能优化分析-数据库优化(中):https://developer.aliyun.com/article/1413678

目录
相关文章
|
5天前
|
存储 SQL Apache
Apache Doris 开源最顶级基于MPP架构的高性能实时分析数据库
Apache Doris 是一个基于 MPP 架构的高性能实时分析数据库,以其极高的速度和易用性著称。它支持高并发点查询和复杂分析场景,适用于报表分析、即席查询、数据仓库和数据湖查询加速等。最新发布的 2.0.2 版本在性能、稳定性和多租户支持方面有显著提升。社区活跃,已广泛应用于电商、广告、用户行为分析等领域。
Apache Doris 开源最顶级基于MPP架构的高性能实时分析数据库
|
1天前
|
SQL druid 数据库
如何进行数据库连接池的参数优化?
数据库连接池参数优化包括:1) 确定合适的初始连接数,考虑数据库规模和应用需求;2) 调整最大连接数,依据并发量和资源状况;3) 设置最小空闲连接数,平衡资源利用和响应速度;4) 优化连接超时时间,确保系统响应和资源利用合理;5) 配置连接有效性检测,定期检查连接状态;6) 调整空闲连接回收时间,适应访问模式并配合数据库超时设置。
|
4天前
|
缓存 监控 NoSQL
数据库如何进行性能优化?
【10月更文挑战第31天】数据库如何进行性能优化?
11 3
|
7天前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
40 4
|
6天前
|
SQL 缓存 监控
数据库优化
【10月更文挑战第29天】数据库优化
14 1
|
6天前
|
缓存 关系型数据库 MySQL
如何优化 MySQL 数据库的性能?
【10月更文挑战第28天】
24 1
|
8天前
|
XML Java 数据库连接
如何使用HikariCP连接池来优化数据库连接管理
在Java应用中,高效管理数据库连接是提升性能的关键。本文介绍了如何使用HikariCP连接池来优化数据库连接管理。通过引入依赖、配置参数和获取连接,你可以显著提高系统的响应速度和吞吐量。 示例代码展示了从配置到使用的完整流程,帮助你轻松上手。
35 3
|
8天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
22 2
|
8天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第27天】本文深入探讨了MySQL的索引策略和查询性能调优技巧。通过介绍B-Tree索引、哈希索引和全文索引等不同类型,以及如何创建和维护索引,结合实战案例分析查询执行计划,帮助读者掌握提升查询性能的方法。定期优化索引和调整查询语句是提高数据库性能的关键。
40 0
|
8天前
|
监控 关系型数据库 MySQL
数据库优化:MySQL索引策略与查询性能调优实战
【10月更文挑战第26天】数据库作为现代应用系统的核心组件,其性能优化至关重要。本文主要探讨MySQL的索引策略与查询性能调优。通过合理创建索引(如B-Tree、复合索引)和优化查询语句(如使用EXPLAIN、优化分页查询),可以显著提升数据库的响应速度和稳定性。实践中还需定期审查慢查询日志,持续优化性能。
35 0

热门文章

最新文章