系统性能调优

文章目录

  • [一. 概念](#一. 概念)
  • [二. 一般流程](#二. 一般流程)
    • [1. 性能测试](#1. 性能测试)
    • [2. 瓶颈分析](#2. 瓶颈分析)
    • [3. 调优手段](#3. 调优手段)
    • [4. 注意事项](#4. 注意事项)
  • [三. 数据库优化](#三. 数据库优化)
    • [1. 硬件配置-升级硬件](#1. 硬件配置-升级硬件)
    • [2. 表设计优化](#2. 表设计优化)
    • [3. 索引优化](#3. 索引优化)
    • [4. 分库分表-适用于数据量较大的表](#4. 分库分表-适用于数据量较大的表)
      • [1. 分库](#1. 分库)
        • [1. 概念](#1. 概念)
        • [2. 分库策略](#2. 分库策略)
          • [1. 按业务模块分库](#1. 按业务模块分库)
          • [2. 按地区分库](#2. 按地区分库)
      • [2. 水平分表-根据数据行拆分](#2. 水平分表-根据数据行拆分)
      • 3.垂直分表-根据字段拆分
      • [4. 实战:-shardingsphere(开源的分布式数据库中间件)](#4. 实战:-shardingsphere(开源的分布式数据库中间件))
        • [1. 架构](#1. 架构)
        • [2. 核心功能](#2. 核心功能)
        • [3. 分片规则](#3. 分片规则)
      • [5. 分开分表可能带来的问题](#5. 分开分表可能带来的问题)
        • [1. 事务一致性问题](#1. 事务一致性问题)
        • [2. 跨节点关联查询join问题](#2. 跨节点关联查询join问题)
        • [3. 全局唯一ID问题](#3. 全局唯一ID问题)
        • [4. 分布式事务问题](#4. 分布式事务问题)
    • [5. 数据缓存](#5. 数据缓存)
    • [6. 查询语句优化](#6. 查询语句优化)
  • [四. 适合加索引的字段以及索引失效的场景](#四. 适合加索引的字段以及索引失效的场景)
    • [1. 适合加索引的字段](#1. 适合加索引的字段)
    • [2. 不适合加索引的字段](#2. 不适合加索引的字段)
    • [3. 索引失效的场景](#3. 索引失效的场景)

一. 概念

通过各种手段优化软件系统的性能,以达到我们预期的运行速度、响应时间、资源使用效率。

二. 一般流程

1. 性能测试

通过性能测试工具(Jmeter、LoadRunner)对系统进行压力测试,获取基本数据.

2. 瓶颈分析

根据测试结果,定位性能瓶颈-cpu、内存、I/O操作、数据库查询等.

3. 调优手段

1.硬件层面:增加服务器数量或升级配置-增加内存、使用更快的硬盘

2.系统配置:优化操作系统和中间件的配置参数,线程池大小、微服务xms、xmx的值(堆内存大小)

3.应用层面:代码优化:利用缓存、分布式部署等提高性能

4.数据库优化:表设计优化、数据库分库分表、索引优化、查询语句优化等,

4. 注意事项

1.需求明确:调优前明确性能目标,比如流程启动:响应时间不超过3秒,并发数为600/分钟

2.监控工具:合理使用监控工具,确保优化效果.

三. 数据库优化

1. 硬件配置-升级硬件

2. 表设计优化

2.1 三范式

2.2 选择合适数据类型:整型代替字符型

2.3 避免使用大字段

2.4 根据业务进行适当的字段冗余,减少关联查询

2.5 进行适当的拆分和关联

3. 索引优化

根据查询频率和条件,创建合适的索引,删除不必要的索引,来提高查询效率

4. 分库分表-适用于数据量较大的表

将数据拆分到多个数据库或者表中,提高读写性能.

1. 分库

1. 概念

将数据拆分到不同的数据库实例中,从而减少单个数据库的访问压力:

2. 分库策略
1. 按业务模块分库
  1. 适用场景:适用于大型系统,不同业务模块之间的数据关联较少。
  2. 示例:将用户模块、订单模块、支付模块分别存储在不同的数据库中。
  3. 优点:减少单个数据库的负载,提高系统的可扩展性和可用性。
  4. 缺点:跨库查询较复杂,需要分布式事务管理。
2. 按地区分库
  1. 适用场景:适用于多地区分布的业务,如电商、物流等。
  2. 示例:将不同地区的用户数据存储在不同的数据库中,如 db_cn 、 db_us 等。
  3. 优点:减少网络延迟,提高查询效率,便于数据的本地化管理。
  4. 缺点:跨地区查询较复杂,需要分布式事务管理。

2. 水平分表-根据数据行拆分

1.概念
  1. 将表中的行分散到多个表中,每个表的结构相同,但数据行不同。
  2. 例如,将用户数据按地区或时间分表。
2.水平分表策略
1.按时间分表
  1. 适用场景:适用于日志数据、历史记录等按时间顺序增长的数据。
  2. 示例:将用户操作日志按月份分表,如 log_202401 、 log_202402 等。
  3. 优点:便于数据的归档和清理,老数据可以定期迁移到冷存储。
  4. 缺点:跨表查询较复杂,需要联合查询多个表。
2.按范围分表
  1. 适用场景:适用于数据有明显范围划分的场景,如用户ID、地区等。
  2. 示例:将用户数据按用户ID范围分表,如 user_0_10000 、 user_10001_20000 等。
  3. 优点:查询效率高,每个表的数据量相对较小。
  4. 缺点:需要维护分表规则,跨表查询较复杂。
3. 按哈希分表
  1. 适用场景:适用于数据分布均匀的场景,如用户ID、订单ID等。
  2. 示例:将用户数据按用户ID的哈希值分表,如 user_0 、 user_1 等,哈希值取模N(N为表的数量)。
  3. 优点:数据分布均匀,查询效率高。
  4. 缺点:跨表查询较复杂,扩展性较差,增加或减少表的数量时需要重新分配数据。

3.垂直分表-根据字段拆分

1.概念
  1. 将表中的列分散到多个表中,每个表包含部分列。
  2. 例如,将用户的基本信息和详细信息分别存储在不同的表中。
2.分表策略
1. 按业务逻辑分表
  1. 适用场景:适用于表中列较多,且不同列的访问频率差异较大的场景。
  2. 示例:将用户表分为基本信息表 user_basic 和详细信息表 user_detail 。
  3. 优点:减少单表的列数,提高查询效率,减少锁竞争。
  4. 缺点:增加了表之间的关联复杂度,需要多表连接查询。
2.按访问频率分表
  1. 适用场景:适用于表中部分列访问频繁,部分列访问较少的场景。
  2. 示例:将订单表分为订单基本信息表 order_basic 和订单扩展信息表 order_extend 。
  3. 优点:提高热点数据的查询效率,减少锁竞争。
  4. 缺点:增加了表之间的关联复杂度,需要多表连接查询。

4. 实战:-shardingsphere(开源的分布式数据库中间件)

1. 架构

核心层、中间件层、存储层

2. 核心功能

数据分片、分布式事务

3. 分片规则
  1. 在配置文件中进行中间件配置,通过tablestrategy(表分片策略)/databasestrategy(数据库分片策略)来设置shardingcolumn(分片字段)
yaml 复制代码
dataSources:
  ds0:
    type: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/ds0
    username: root
    password: root
  ds1:
    type: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.cj.jdbc.Driver
    jdbcUrl: jdbc:mysql://localhost:3306/ds1
    username: root
    password: root

sharding:
  tables:
    orders:
      actualDataNodes: ds${0..1}.orders_${0..1} # 指定了实际的数据节点,ds0 和 ds1 是数据库实例,orders_0 和 orders_1 是表名,表示数据被拆分到这些表中
      tableStrategy: # 定义了表分片策略,order_id 字段的模值决定了数据应存储到哪个表中
        inline:
          shardingColumn: order_id
          algorithmExpression: orders_${order_id % 2}
      databaseStrategy: # 定义了数据库分片策略,order_id 字段的模值决定了数据应存储到哪个数据库中
        inline:
          shardingColumn: order_id
          algorithmExpression: ds${order_id % 2}
  defaultDatabaseStrategy:
    none:

5. 分开分表可能带来的问题

1. 事务一致性问题
  1. 跨库事务 :分库后,若一个事务需操作多个数据库实例,如更新分布在不同库中的用户表和订单表,传统单机数据库的事务特性(ACID)无法直接保证,会出现原子性、一致性、隔离性、持久性问题,如事务中某步骤失败,回滚困难,部分操作成功部分失败致数据不一致,或部分数据库提交事务而另一部分因故障未提交等。
  2. 跨表事务:即使在同数据库实例中,数据分散到不同表,更新主表和多个分表时,也难在不增复杂度情况下确保事务原子性。
2. 跨节点关联查询join问题

拆分前,列表和详情表数据可通过join连表查询完成,切分后数据分布在不同节点,join查询变得麻烦,且为保证性能,应尽量避免使用join查询。

3. 全局唯一ID问题

分库分表后,每张表的自增ID仅在本表唯一,无法保证全局唯一,如订单表1和订单表2的主键都从1开始,在需全局唯一ID的场景会发生冲突。

4. 分布式事务问题

跨库事务需特别注意,可采用分布式事务框架如Seata或XA协议来保证一致性。

5. 数据缓存

6. 查询语句优化

1.根据慢查询日志,定位sql
  
  开启慢查询-设置慢查询时间-查询日志文件-确定当前sql的具体响应时间
	# 通过Mysql的set命令开启慢查询
	1.1 set global slow_query_log='ON';
	# 记录慢查询日志的保存位置
	1.2 set global slow_query_log_file='/usr/local/mysql/data/slow.log';
	# 设置查询响应时间阈值-2秒以上为慢查询,记录该条sql到慢查询日志中
	1.3 set global long_query_time=2;

2.使用explain 分析该sql,确认是否在使用索引,索引的适用是否正确.
  
  关注点1:type属性

  all-全表扫描;index:指从索引中读取想要的数据
  
  比如:explain select count(id_) from PORTAL_SYS_LOGS;从索引中读取行数量

  关注点2: extra属性

  using index:所有被查询的字段都是索引列(覆盖索引)
 
  using where:被查询的列未被索引覆盖	

3.修改sql或者使用索引

四. 适合加索引的字段以及索引失效的场景

1. 适合加索引的字段

1)主键字段:用于唯一标识每个记录的字段,通常是数据库表中的一个自增或唯一标识字段。

2)外键字段:用于连接两个表之间关系的字段,通常是一个表中的字段与另一个表中的主键字段关联。

3)经常用于查询的字段:如果某个字段经常被用于查询条件,例如用户的用户名、邮箱或订单的编号,那么为该字段添加索引可以提高查询性能。

4)经常用于排序的字段:如果某个字段经常用于排序操作,例如文章的发布时间或销售订单的日期,为该字段添加索引可以加快排序操作的速度。

5)经常用于连接操作的字段:如果某个字段用于连接多个表进行关联查询,例如用户表和订单表中的用户 ID 字段,为该字段添加索引可以提高连接操作的性能。

总结:Select、Where、Join、Order By 后面跟着的字段建议加索引。

2. 不适合加索引的字段

1)低选择性的列:低选择性的列指的是具有很少不同值的列。如果一列只有很少几个不同的值,那么为它添加索引可能不会提供显著的性能改进,而且可能浪费存储空间。例如,性别列通常只有两个不同的值(男和女),对其添加索引通常没有太大意义。

2)频繁更新的列:如果一个列经常被更新,特别是大规模的批量更新,那么索引会增加更新操作的开销。每次更新索引列都需要维护索引结构,这可能会导致性能下降。在这种情况下,需要仔细权衡查询性能和更新性能。

3)小表:对于非常小的表,查询通常非常快,即使没有索引。在这种情况下,添加索引可能只会增加存储开销,而不会明显提高性能。

总结:低选择性、频繁更新、数据量较小的表不推荐加索引。

3. 索引失效的场景

1)左或左右模糊匹配,因为 MySQL 采用最左匹配原则。

SELECT * FROM users WHERE name LIKE '%abc';

2)查询条件中队索引列使用函数。

SELECT * FROM users WHERE LOWER(name) = 'abc';

3)查询条件对索引列使用表达式计算。

SELECT * FROM users WHERE age + 10 = 30;

4)字段类型不一致导致索引失效-如果索引列是字符串,输入参数是数字,那么索引列会产生隐式类型转换,CAST 函数实现,等同于对索引列使用函数,导致索引失效,反之索引列是数字,输入参数是字符串,那么不会失效。

SELECT * FROM users WHERE str = 1234 ;

5)在 Where 子句中,如果在 OR 前的条件列是索引列,但 OR 后面的条件列不是索引列。

SELECT * FROM users WHERE name = 'abc' OR age = 30;

6)使用 Select * 语句,大概率不会走索引,因为不是每一列都加索引。

SELECT * FROM users;

7)使用 Not Exists /IN关键字,索引也会失效,本质上是 Where 查询范围过大。

SELECT * FROM users WHERE NOT EXISTS (SELECT * FROM orders WHERE orders.user_id = users.id);

select * from logs where log_type in ('业务日志','异常日志');

8)使用 Order by 注意最左匹配,并且要加 limit 或者 Where 关键字,否则索引会失效。

SELECT * FROM users ORDER BY name LIMIT 10;

相关推荐
宁静@星空42 分钟前
006-excel数据输出insert语句
数据库·mysql·excel
七禾页话1 小时前
数据库基础知识总结
数据库
黄团团1 小时前
Vue2+OpenLayers实现车辆开始、暂停、重置行驶轨迹动画(提供Gitee源码)
前端·javascript·数据库·vue.js·gitee·html
打码人的日常分享1 小时前
智慧城市视联网一体化平台整体解决方案(Word原件)
大数据·数据库·人工智能·智慧城市·规格说明书
A_cainiao_A2 小时前
【软考】【2025年系统分析师拿证之路】【啃书】第五章 数据库系统(六)
数据库·oracle
一个假的前端男2 小时前
宝塔自动备份数据库到阿里云 OSS
数据库·阿里云·云计算
Navicat中国2 小时前
Navicat Premium 原生支持阿里云 PolarDB 数据库
数据库·sql·mysql·阿里云·postgresql·云计算·navicat
Jacob_AI2 小时前
大模型——RAG
数据库·人工智能·算法
Run Out Of Brain2 小时前
MySQL教程之:常见查询示例
数据库·mysql
我是前端小学生3 小时前
MySQL 语法树解析:深入理解数据库查询处理的核心环节
数据库