前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >性能工程之中级系列之四

性能工程之中级系列之四

作者头像
高楼Zee
发布2021-04-01 11:21:28
4740
发布2021-04-01 11:21:28
举报
文章被收录于专栏:7DGroup7DGroup

erp登录接口之mysql调优

一、前言

为了方便跟踪系统tps变动,这次采用 Grafana 展示结果,而且采用 docker 安装部署 influxdb 与 grafana ,参考命令如:

代码语言:javascript
复制
mkdir -p /home/influxdb/data /home/influxdb/conf /home/influxdb/meta /home/influxdb/wal
docker pull influxdb
docker search grafana
docker pull docker.io/grafana/grafana
docker run -d -p 8083:8083 -p 8086:8086 --name influxdb influxdb

docker run -d -p 3000:3000 --name=grafana -v /data/grafana:/var/lib/grafana grafana/grafana

docker exec -it 219f8baad500 bash
root@219f8baad500:/# influx
Connected to http://localhost:8086 version 1.8.3
InfluxDB shell version: 1.8.3
> CREATE database jmeter;
> SHOW DATABASES;
name: databases
name
----
_internal
jmeter
>

其他部署安装略也可以参考性能工具之Jmeter小白入门系列之六,目前该数据库配置结果为:

Grafana展示结果如:

一、登录代码分析

在上一讲中已经发现sql没有建立索引问题,这一节一起从代码层去分析为什么没有建立索引,打开idea找到登录请求资源路径位置如:

代码语言:javascript
复制
@PostMapping(value = "/login")
public BaseResponseInfo login(@RequestParam(value = "loginName", required = false) String loginName,
                    @RequestParam(value = "password", required = false) String password,
                    HttpServletRequest request)throws Exception {

1、找到登录 Controller 调 service 位置

2、找到方法实现层:

解释:从上面代码可以看出,用户登录传入用户名密码,代码根据用户去DAO层去查询是否有该用户;

说明:Dao层就是常规写法,没有什么特别地方,再跳转xml文件查看sql是怎么写的:

说明:根据条件查询全部数据,既然这是登录接口传入的是用户名,那么应该在用户名处增加用户索引,这样查询能加快速度;

索引类似于字典目录,通过索引能快速找到响应数据;

解释:如果查询为空或者查询结果为0表示数据库么有数据直接返回用户不存在,如果存在在往下走走;

解释:如果上面都通过,这里又根据用户名密码查询数据库,这里作者为什么要查询两次数据库,既然上面已经查询完全可以在内存做判断;假如数据库有1000千用户数,每个用户登录都需要查询两次数据,也是一笔不小的开支;

二、索引优化

上节课已经发现索引有问题,但是发现用户表数据很少,第一步先增加用户数据,再通过Jmeter进行压测,造数据在性能测试中是常见的事件,这次造数据直接通过 java for 循环造数据代码参考如下:

代码语言:javascript
复制
/**
 * @description: 注册用户
 * @author: 李文
 * @create: 2021-03-19 21:03
 **/
@RunWith(SpringRunner.class)
@SpringBootTest
public class LoginRegTest {

    @Resource
    private UserMapper userMapper;

    @Test
    public void contextLoads() {


        try {
            for (int j = 0; j < 100; j++) {
                for (int i = 0; i < 1000; i++) {
                    UserEx userEx = new UserEx();
                    userEx.setLoginName(RandomUtil.randomString(10));
                    userEx.setUsername(RandomUtil.randomString(8));
                    userEx.setEmail(RandomUtil.randomInt(1, 1100) + "@7DGroup.com");
                    userEx.setPassword(Tools.md5Encryp(BusinessConstants.USER_DEFAULT_PASSWORD));
                    userEx.setIsystem(BusinessConstants.USER_NOT_SYSTEM);
                    userEx.setIsmanager(BusinessConstants.USER_NOT_MANAGER);
                    userEx.setStatus(BusinessConstants.USER_STATUS_NORMAL);
                    userMapper.insert(userEx);
                }
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}

再次打开mysql客户端输入如下sql语句:

代码语言:javascript
复制
mysql> SELECT count(*) from `jsh_user`;
+----------+
| count(*) |
+----------+
| 333724   |
+----------+
1 行于数据集 (0.07 秒)

mysql> SELECT count(*) from `jsh_user`;

EXPLAIN SELECT id,username,login_name, PASSWORD,position, department, email, phonenum, ismanager, isystem, STATUS, description, remark, tenant_id
FROM
  jsh_user
WHERE
  (
    login_name = "admin"
    AND PASSWORD = "e10adc3949ba59abbe56e057f20f883e"
    AND STATUS = 0
  );
+----------+
| count(*) |
+----------+
| 333724   |
+----------+
1 行于数据集 (0.05 秒)

+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| 1  | SIMPLE      | jsh_user | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 331551 | 0.10     | Using where |
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 行于数据集 (0.06 秒)

mysql> 
 

图片如下:

为了减少性能消耗,这次都采用后台运行,把项目跑起来显现如下:

Jmeter运行结果如下:

代码语言:javascript
复制
liwen@liwen123 hunhe % jmeter -n -t he1.jmx
Creating summariser <summary>
Created the tree successfully using he1.jmx
Starting standalone test @ Fri Mar 19 22:01:53 CST 2021 (1616162513949)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary +     44 in 00:00:06 =    7.8/s Avg:   534 Min:   472 Max:   910 Err:     0 (0.00%) Active: 9 Started: 9 Finished: 0
summary +    336 in 00:00:30 =   11.2/s Avg:  2129 Min:   537 Max:  3626 Err:     0 (0.00%) Active: 30 Started: 30 Finished: 0
summary =    380 in 00:00:36 =   10.7/s Avg:  1944 Min:   472 Max:  3626 Err:     0 (0.00%)

运行几分钟结果如下:

增加索引语句:

代码语言:javascript
复制
ALTER TABLE `jsh_user` ADD INDEX index_name ( `login_name` )

增加索引结果如下:

调优结果:

jmeter后台数据如下:

说明:通过直接增加索引TPS明显增加;

三、复习Mysql索引

Mysql索引分为:

(1)主键索引 PRIMARY KEY:它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引。

(2) 唯一索引 UNIQUE:

代码语言:javascript
复制
ALTER TABLE table_name ADD UNIQUE (column)

(3) 普通索引 INDEX

代码语言:javascript
复制
ALTER TABLE table_name ADD INDEX index_name (column)

(4) 组合索引 INDEX

代码语言:javascript
复制
ALTER TABLE table_name ADD INDEX index_name(column1, column2, column3)

(5) 全文索引 FULLTEXT

代码语言:javascript
复制
ALTER TABLE table_name ADD FULLTEXT (column)

查看索引:

代码语言:javascript
复制
mysql> show index from  jsh_user;
+----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
| Table    | Non_unique | Key_name   | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment | Visible |
+----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
| jsh_user | 0          | PRIMARY    | 1            | id          | A         | 3           | NULL     | NULL   |      | BTREE      |         |               | YES     |
| jsh_user | 1          | index_name | 1            | login_name  | A         | 331551      | NULL     | NULL   |      | BTREE      |         |               | YES     |
+----------+------------+------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+---------+
2 行于数据集 (0.02 秒)

mysql>

删除索引:

代码语言:javascript
复制
ALTER TABLE  jsh_user DROP INDEX  index_name;

更多mysql调优请参考《性能测试实战30讲》中的:

https://time.geekbang.org/column/article/196791《22丨MySQL:数据库级监控及常用计数器解析(上)》

https://time.geekbang.org/column/article/197432 《23丨MySQL:数据库级监控及常用计数器解析(下)》

四、总结

性能调优是一个反复验证尝试的过程,但调优步骤是固定。在这一节中通过观察代码步骤来跟踪并理解为什么在用户名上面增加索引,通过边压测边增加索引看到调优结果;

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 7DGroup 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、前言
  • 一、登录代码分析
  • 二、索引优化
  • 三、复习Mysql索引
  • 四、总结
相关产品与服务
数据库
云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档