性能测试学习第十天-----性能案例分析之数据库性能问题

景泽元的编程 2019-10-21

一、现象 /pinter/case/slow?userName=xxx
  tps很低,响应时间很长,数据库服务器cpu很高(接近100%),应用服务器负载比较低
  索引
  索引是对数据库表中一列或多列的值进行排序的一种结构,存储了表中的关键字段,使用索引可快速访问数据库表中的特定信息。类似于书籍中的目录。
二、分析

数据库服务器CPU高,一般都是因为SQL执行效率低导致的,可能有三方面原因
    1、数据库表缺少必要的索引;
    2、索引不生效
    3、SQL不够优化

三、慢查询

在MySQL中,可以监控SQL语句的执行效率,并分析SQL使用索引的情况,从而协助定位性能问题,慢SQL的配置和抓取配置方法如下:

1 、 开启 开启慢 慢 SQL 的配置
  1.1 LIUNX 系统 在 mysql 配置文件 my.cnf 中增加
    slow_query_log
    slow_query_log_file=/usr/local/mysql/data/zhoucentos-slow.log
    long_query_time=0.1
  ? Slow_query_log 这是一个布尔型变量,默认为真。没有这变量,数据库不会打印慢查询的日志。
  ? log-slow-log_file=/export/servers/mysql/bin/mysql_slow.log (指定日志文件存放位置,可以为空,系统会给一个缺省的文件 host_name-slow.log)
  ? long_query_time=0.1(记录超过的时间,默认为 10s),与 DBA 沟通,性能测试分析问题时可以将该值设为 0.1 即 100 毫秒,这样分析的粒度更详细。
  备选 :log-queries-not-using-indexes (log 下来没有使用索引的 query,可以根据情况决定是否开启)。log-long-format (如果设置了,所有没有使用索引的查询也将被记录)
  1.2 Windows 下配置:  在 my.ini 的[mysqld]添加如下语句:
    log-slow-queries = E:\web\mysql\log\mysqlslowquery.log
    long_query_time = 0.1(其他参数如上)
    注: 配置完成后,重新 mysql 服务配置才能生效。
  2 、 慢查询开启与关闭
  2.1 配置完成,连接数据库检查慢查询日志是否开启:
    命令如下:mysql> show variables like ‘%slow_query_log%‘;
  2.2 如果没有打开,请开启,slow_query_log
    开启命令:mysql> set @@global.slow_query_log = on;
    关闭命令:mysql> set @@global.slow_query_log = off;
  2.3 再次检查是否开启成功:    mysql> show variables like ‘%slow_query_log%‘;
  2.4 检查目录中是否生成文件:/mysql 目录下是否存在 mysql_slow.log
    [ mysql]# ls -l mysql_slow.log
  3 、 慢查询日志分析            

3.1 Linux 系统:    

  SQL 语句的执行信息

  常用命令,通过 mysqldumpslow –help 查看
    ? -s,是 order 的排序,主要有 c,t,l,r 和 ac,at,al,ar,分别是按照 query 次数,时间,lock 的时间和返回的记录数来排序
    ? -a,倒序排列
    ? -t,是 top n 的意思,即为返回前面多少条的数据
    ? -g,后边可以写一个正则匹配模式,大小写不敏感的
  例如: mysqldumpslow -s c -t 20 host-slow.log
      mysqldumpslow -s r -t 20 host-slow.log
    上述命令分别可以看出访问次数最多的 20 个 sql 语句和返回记录集最多的 20 个 sql。
  mysqldumpslow -t 10 -s t -g “left join” host-slow.log 这个是按照时间返回前 10条里面含有左连接的 sql 语句。
  使用 mysql 自带命令 mysqldumpslow ,在mysql/bin目录下执行 mysqldumpslow –s at -t 50 host-slow.log 显示出耗时最长的 50 个,注意慢查询日志log路径带全
  以 Count: 32 Time=0.26s (8s) Lock=0.00s (0s) Rows=10.0 (320),
  wos_20120719[wos_20120719]@2host 为例:
    Count: 32 该 SQL 总共执行 32 次
    Time = 0.26s (8s) 平均每次执行该 SQL 耗时 0.26 秒,总共耗时 32(次)*0.26(秒)=8 秒。
    Lock=0.00s(0s) lock 时间 0 秒
    Rows =10.0(320) 每次执行 SQL 影响数据库表中的 10 行记录,总共影响 10(行)*32(次)=320 行记录
  3.2 Windows 系统:
  当你是第一次开启 mysql 的慢查询,会在你指定的目录下创建这个记录文件,本文就是mysqlslowquery.log,这个文件的内容大致如下(第一次开启 MYSQL 慢查询的情况下)
  E:\web\mysql\bin\mysqld, Version: 5.4.3-beta-community-log (MySQLCommunity Server (GPL)). started with:TCP Port: 3306, Named Pipe: (null) Time Id Command Argument
  可以通过如下的命令来查看慢查询的记录数:
    mysql> show global status like ‘%slow%’;
    +———————+——-+
    | Variable_name | Value |
    +———————+——-+
    | Slow_launch_threads | 0 |
    | Slow_queries | 0 |
    +———————+——-+

四、执行计划

  执行计划
  在sql语句前加上explain,可以分析这条sql语句的执行情况
  explain select * from teacher where
  Type列可能的值
  Const:表中只有一个匹配行,用到primary key或unique key
  Eq_ref:唯一性索引扫描,key的所有部分被连接联接查询使用,且key是unique或primary key
  ref:非唯一性索引扫描,或只使用了联合索引的最左前缀
  Range:索引范围扫描,在索引列上进行给定范围内的检索,如between,in(1,100)
  Index:遍历索引...
  All:全表扫描
  Prossible key:使用哪个索引能找到行
  Keys:sql语句使用的索引
  rows:mysql 根据索引选择情况,估算查找数据所需读取的行数

五、联合索引  

联合索引,比单个索引性能更好
  一个索引同时作用于多个字段,一个索引建议不超过4个字段
  联合索引的最左前缀
  联合索引检索数据时,会从最左边开始匹配(忽略sql字段顺序),如果匹配不到,就不使用索引
  如:User表有联合索引my_index(A字段,B字段,C字段)

        性能测试学习第十天-----性能案例分析之数据库性能问题

 六、连接数  

连接数监控命令
show variables like ‘%connections%‘
show status like ‘%thread%
其中:
Threads_connected 当前打开的连接的数量
Threads_cached 线程缓存内的线程的数量
Threads_created 创建的线程数
Threads_running 激活的(非睡眠状态)线程数
show status like ‘%connection%‘
Connections 试图连接MySQL服务器的次数

七、数据库架构优化

架构优化
读写分离,主从配置
分库分表,根据一个固定的算法来路由库名和表名,如id%10,1202922292
user_1
user_2
user_3
...
user_10
硬件调优
使用更好的物理磁盘介质,如SSD、fusionIO卡等

八、SQL优化

常见的一些sql优化方案
1、在 where 及 order by 涉及的列上建立索引,避免全表扫描,索引不要太多,一个表一般不要
超过4个索引
2、避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
3、查询语句中不要使用 *,减少内存使用
4、尽量减少子查询,使用关联查询(left join,right join,inner join)替代
5、减少使用IN或者NOT IN ,使用exists,not exists或者关联查询语句替代
6、or 的查询尽量用 union或者union all 代替(在确认没有重复数据或者不用剔除重复数据时,
union all会更好)
7、合理的增加冗余的字段(减少表的联接查询)
8、建表的时候能使用数字类型的字段就使用数字类型(type,status...),数字类型的字段作为条
件查询比字符串的快

九、代码优化

代码优化原则
1、使用对象池减少对重复对象的创建;
2、调整对后端的连接
3、增加本地缓存
4、如果不涉及事务的情况下,考虑使用Nosql进行存储
5、一次请求合并多次操作
6、由串行修改为并行操作
7、同步修改为异步

十、性能瓶颈定位思路(面试必问)

整体思路:从前到后,从表象到内部
1、首先排除压力机自身的问题,如CPU、内存,网络,脚本编写等
2、监控中间件的访问日志,观察响应时间,大体确定耗时处于哪一段
3、排查网络问题,监控压力机到后端服务器的网络,以及各服务器间的网络,是否达到网络上限
4、监控服务端所有机器的操作系统负载,如CPU、内存、磁盘、网络是否达到瓶颈
5、监控应用服务器的日志,查看是否存在ERROR日志,比如TimeOut或其他类型报错
6、监控各中间件的连接数,如nginx、tomcat、mysql等,是否达到上限
7、监控应用程序线程状态,使用jstack或jvisualvm查看是否有死锁、阻塞等情况
8、监控应用程序的jvm,使用jstat或者jmap查看GC情况,是否内存泄漏等
9、使用jprofiler监控应用程序,可以查看耗时比较长的代码方法
10、监控数据库,是否存在慢查询,一般数据库CPU高都是因为SQL语句效率低造成的
11、检查数据库执行计划,是否有全表扫描,以及索引不生效的情况
12、检查系统外部依赖情况,如果外部依赖系统性能差,也会造成本系统性能低
13、对于不好定位的问题,可以考虑采用模块隔离法来确定问题 

相关推荐