【文件增量备份系统】MySQL百万量级数据量分页查询性能优化

🎯 导读:本文针对大数据量下的分页查询性能问题进行了深入探讨与优化,最初查询耗时长达12秒,通过避免全表计数及利用缓存保存总数的方式显著提升了浅分页查询速度。面对深分页时依然存在的延迟,采用先查询倒数第N条记录ID,再依据此ID获取后继记录的策略,进一步降低了查询时间。此方案适用于优化大量数据背景下的分页展示性能问题。
🏠️ 项目仓库:数据增量备份系统
📙 项目介绍:【文件增量备份系统】系统功能介绍与开源说明

文章目录

  • 问题说明
  • 原因排查
  • total查询优化
    • 实现步骤
      • 在缓存类中添加一个原子类的备份文件总数属性
      • 实现一个更新缓存值的方法
      • 在项目启动成功之后,调用上面方法记录total值
      • 修改分页查询方法:在分页查询的时候,不要查询总数,总数从缓存中读取
      • 新增文件、删除文件时更新缓存值
    • 测试
  • 深分页问题优化
    • 问题说明
    • 优化实现
    • 测试
    • explain效率比较分析
  • 总结

问题说明

当数据量达到百万级时,查询性能已经非常慢了

在这里插入图片描述
经过查看日志,可以发现查询一次接口,耗时高达 两年半 5 秒,而且查的还是第一页,等查完数据,黄花菜都凉了,受不了一点,为了用户的体验,必须改进

原因排查

原始代码如下,对id进行降序排序是因为id是递增的,id越大,代表文件备份时间越新。对id进行排序是为了把最新备份的文件记录放在最前面

@Override
public PageResponse<BackupFile> pageBackupFileV1(BackupFileRequest request, boolean isOrder) {long start = System.currentTimeMillis();QueryWrapper<BackupFile> queryWrapper = new QueryWrapper<>();if (request.getBackupSourceId() != null) {queryWrapper.eq("backup_source_id", request.getBackupSourceId());}if (request.getBackupTargetId() != null) {queryWrapper.eq("backup_target_id", request.getBackupTargetId());}if (!StringUtils.isEmpty(request.getSourceFilePath())) {queryWrapper.like("source_file_path", request.getSourceFilePath());}if (!StringUtils.isEmpty(request.getTargetFilePath())) {queryWrapper.like("target_file_path", request.getTargetFilePath());}queryWrapper.orderByDesc("id");IPage<BackupFile> page = baseMapper.selectPage(new Page(request.getCurrent(), request.getSize()), queryWrapper);System.out.println("分页查询时间:" + (System.currentTimeMillis() - start) + "ms");return PageUtil.convert(page);
}

在这里插入图片描述

通过查看日志,发现在一次分页查询中,主要做两件事情:

  • 查询数据总条数
SELECT COUNT(*) AS total FROM backup_file
  • 进行真正的分页查询
SELECT id,backup_source_id,backup_target_id,source_file_path,target_file_path,backup_num,file_type,last_backup_time,file_name,file_suffix,file_length,file_length_after_compress,father_id,is_compress,is_contain_file,create_time,update_time FROM backup_file ORDER BY id DESC LIMIT 10

那上面慢的是哪个sql呢,还是说两个都慢,分别对两个sql进行单元测试

【查询数据总条数】

==>  Preparing: SELECT COUNT( * ) AS total FROM backup_file
==> Parameters:
<==    Columns: total
<==        Row: 3458533
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@521d455c]
时间:4093ms

【进行真正的分页查询】

==>  Preparing: SELECT id,backup_source_id,backup_target_id,source_file_path,target_file_path,backup_num,file_type,last_backup_time,file_name,file_suffix,file_length,file_length_after_compress,father_id,is_compress,is_contain_file,create_time,update_time FROM backup_file ORDER BY id DESC LIMIT 10
==> Parameters:
<==    Columns: id, backup_source_id, backup_target_id, source_file_path, target_file_path, backup_num, file_type, last_backup_time, file_name, file_suffix, file_length, file_length_after_compress, father_id, is_compress, is_contain_file, create_time, update_time
......
<==      Total: 10
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@327ac23]
时间:25ms

好家伙,原来慢的是查询总数。那为什么这么慢呢?
原因是 COUNT() 需要遍历整个表中的每一行来计算总行数(涉及大量的磁盘I/O操作,尤其是如果数据分布在多个磁盘块上时),因为行数多,所以慢

total查询优化

既然查询total那么久的话,怎么加速total查询呢,最方便的一个方法就是使用缓存。查询一次total就把它放到缓存中,当新增或修改数据时,再更新缓存

实现步骤

在缓存类中添加一个原子类的备份文件总数属性

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;/*** 缓存类** @Author dam* @create 2024/2/19 19:57*/
public class Cache {....../*** 所备份文件的总数量*/public static AtomicLong FILE_TOTAL_NUM = new AtomicLong();
}

实现一个更新缓存值的方法

/*** 更新缓存中的total值*/
@Override
public void updateTotalCache() {Long total = baseMapper.selectCount(new QueryWrapper<BackupFile>().select("id"));FILE_TOTAL_NUM.set(total);
}

在项目启动成功之后,调用上面方法记录total值

import lombok.extern.slf4j.Slf4j;
import org.dam.service.BackupFileService;
import org.dam.service.BackupTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;/*** @Author dam* @create 2024/1/25 19:29*/
@Component
@Slf4j
public class BackupTaskInit implements CommandLineRunner {@Autowiredprivate BackupTaskService backupTaskService;@Autowiredprivate BackupFileService backupFileService;@Overridepublic void run(String... args) throws Exception {log.info("项目启动成功,执行初始化,将没有完成的备份任务设置为失败状态");backupTaskService.updateNotFinishedTask();log.info("项目启动成功,更新备份文件总数缓存");backupFileService.updateTotalCache();}
}

修改分页查询方法:在分页查询的时候,不要查询总数,总数从缓存中读取

@Override
public PageResponse<BackupFile> pageBackupFileV2(BackupFileRequest request, boolean isOrder) {long start = System.currentTimeMillis();QueryWrapper<BackupFile> queryWrapper = new QueryWrapper<>();if (request.getBackupSourceId() != null) {queryWrapper.eq("backup_source_id", request.getBackupSourceId());}if (request.getBackupTargetId() != null) {queryWrapper.eq("backup_target_id", request.getBackupTargetId());}if (!StringUtils.isEmpty(request.getSourceFilePath())) {queryWrapper.like("source_file_path", request.getSourceFilePath());}if (!StringUtils.isEmpty(request.getTargetFilePath())) {queryWrapper.like("target_file_path", request.getTargetFilePath());}queryWrapper.orderByDesc("id");Page<BackupFile> page = new Page<>(request.getCurrent(), request.getSize());// 关闭总记录数统计page.setSearchCount(false);IPage<BackupFile> pageResult = baseMapper.selectPage(page, queryWrapper);List<BackupFile> backupFileList = pageResult.getRecords();PageResponse pageResponse = new PageResponse();pageResponse.setRecords(backupFileList);pageResponse.setCurrent(request.getCurrent());pageResponse.setSize(request.getSize());pageResponse.setTotal(Cache.FILE_TOTAL_NUM.get());System.out.println("分页查询时间:" + (System.currentTimeMillis() - start) + "ms");return pageResponse;
}

新增文件、删除文件时更新缓存值

由于该系统仅为个人使用,对缓存的时效性要求没有那么高,因此我只在备份结束的时候更新缓存值即可

/*** 根据备份任务来进行备份** @param task                备份任务* @param ignoreFileList      忽略文件名列表* @param ignoreDirectoryList 忽略目录名列表*/
private void backUpByTask(Task task, List<String> ignoreFileList, List<String> ignoreDirectoryList) throws IOException {......// 更新备份文件总数缓存backupFileService.updateTotalCache();
}

测试

查询第一页数据仅需要17ms,性能得到了飞一般的提升

在这里插入图片描述

你以为到这里就优化完了吗?不不不,随着分页的深度逐步加深,查询的速度会越来越慢,请继续阅读下面的深分页问题

深分页问题优化

问题说明

在这里插入图片描述
当查看最后一页数据时(数据量有3,459,110条),发现耗时竟然接近 8 秒,性能还是太差了。原因:我们默认的分页是使用offset来实现的,假设有10000条数据,当我们查询最后一页时,即使我们只需要10条数据,数据库也需要先检索出前面的99990条记录并丢弃它们,才能得到我们需要的结果,所以这个过程很慢

==>  Preparing: SELECT id,backup_source_id,backup_target_id,source_file_path,target_file_path,backup_num,file_type,last_backup_time,file_name,file_suffix,file_length,file_length_after_compress,father_id,is_compress,is_contain_file,create_time,update_time FROM backup_file ORDER BY id DESC LIMIT ? OFFSET ?
==> Parameters: 10(Long), 3459100(Long)
......
<==      Total: 10
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3fc32129]
分页查询时间:7712ms

优化实现

首先根据偏移量查询id

<select id="selectIDByOffset" resultType="java.lang.Long">select idfrom backup_fileorder by id desc limit #{offset}, 1
</select>

再根据查询到的 id 来取后面 size 条数据

// 将所有sql包裹在一个事务中执行,避免创建两次SqlSession。设置为只读事务,因为这里没有更新操作
@Transactional(readOnly = true)
@Override
public PageResponse<BackupFile> pageBackupFileV3(BackupFileRequest request, boolean isOrder) {long start = System.currentTimeMillis();request.setOffset((request.getCurrent() - 1) * request.getSize());Long idByOffset = baseMapper.selectIDByOffset((request.getCurrent() - 1) * request.getSize());QueryWrapper<BackupFile> queryWrapper = new QueryWrapper<>();if (request.getBackupSourceId() != null) {queryWrapper.eq("backup_source_id", request.getBackupSourceId());}if (request.getBackupTargetId() != null) {queryWrapper.eq("backup_target_id", request.getBackupTargetId());}if (!StringUtils.isEmpty(request.getSourceFilePath())) {queryWrapper.like("source_file_path", request.getSourceFilePath());}if (!StringUtils.isEmpty(request.getTargetFilePath())) {queryWrapper.like("target_file_path", request.getTargetFilePath());}queryWrapper.orderByDesc("id");queryWrapper.le("id", idByOffset);queryWrapper.last("LIMIT " + request.getSize());List<BackupFile> backupFileList = baseMapper.selectList(queryWrapper);PageResponse pageResponse = new PageResponse();pageResponse.setRecords(backupFileList);pageResponse.setCurrent(request.getCurrent());pageResponse.setSize(request.getSize());pageResponse.setTotal(Cache.FILE_TOTAL_NUM.get());System.out.println("分页查询时间:" + (System.currentTimeMillis() - start) + "ms");return pageResponse;
}

有读者可能有疑问。为什么要分两次查询,不直接用一个子查询sql来实现呢?(例如下面的代码)我测试了,发现浅分页的时候,查询的结果没有问题,深分页之后,查出来的数据和直接分页查询的数据对不上,不知道是不是我用了分表,对子查询产生了影响(有知道的大佬求求在评论区教教我,非常感谢)

select f1.id,f1.backup_source_id,f1.backup_target_id,f1.source_file_path,f1.target_file_path,f1.backup_num,f1.file_type,f1.last_backup_time,f1.file_name,f1.file_suffix,f1.file_length,f1.file_length_after_compress,f1.father_id,f1.is_compress,f1.is_contain_file,f1.create_time,f1.update_time
from backup_file f1
where (select idfrom backup_fileorder by id desc limit #{request.offset} , 1) >= id
order by f1.id desclimit #{request.size}

测试

经过测试,发现最后一页的查询时间为 3.4 s,又把时间减少了一半

Creating a new SqlSession
Registering transaction synchronization for SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cbb45b9]
JDBC Connection [HikariProxyConnection@1178808009 wrapping org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection@2c08fcbd] will be managed by Spring
==>  Preparing: select id from backup_file order by id desc limit ?, 1
==> Parameters: 3459100(Long)
<==    Columns: id
<==        Row: 1760179379180195842
<==      Total: 1
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cbb45b9]
Fetched SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cbb45b9] from current transaction
==>  Preparing: SELECT id,backup_source_id,backup_target_id,source_file_path,target_file_path,backup_num,file_type,last_backup_time,file_name,file_suffix,file_length,file_length_after_compress,father_id,is_compress,is_contain_file,create_time,update_time FROM backup_file WHERE (id <= ?) ORDER BY id DESC LIMIT 10
==> Parameters: 1760179379180195842(Long)
.....
Releasing transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cbb45b9]
分页查询时间:3492ms
Transaction synchronization committing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cbb45b9]
Transaction synchronization deregistering SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cbb45b9]
Transaction synchronization closing SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4cbb45b9]

explain效率比较分析

通过单元测试,发现时间主要花费在根据偏移量查询id,后面根据偏移 id 来查询数据就很快了。

==> Parameters:
<==    Columns: id
<==        Row: 1760179379180195842
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@46b4d4e7]
id:1760179379180195842
查id时间:3169msCreating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3387d45e] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1063860793 wrapping org.apache.shardingsphere.driver.jdbc.core.connection.ShardingSphereConnection@1ef7e4c7] will not be managed by Spring
==>  Preparing: select id, backup_source_id, backup_target_id, source_file_path, target_file_path, backup_num, file_type, last_backup_time, file_name, file_suffix, file_length, file_length_after_compress, father_id, is_compress, is_contain_file, create_time, update_time from backup_file where ? >= id order by id desc limit 10
==> Parameters: 1760179379180195842(Long)
......
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@3387d45e]
查数据时间:27ms

【直接分页查询】

explain SELECT id,backup_source_id,backup_target_id,source_file_path,target_file_path,backup_num,file_type,last_backup_time,file_name,file_suffix,file_length,file_length_after_compress,father_id,is_compress,is_contain_file,create_time,update_time FROM backup_file_5 ORDER BY id DESC LIMIT 1000,10

在这里插入图片描述

  • 查询类型(type)为"index",这意味着MySQL正在执行全索引扫描。这通常意味着查询只访问索引树上的数据,而不需要回表获取其他列的信息。
  • possible_keys 列显示为空,表示没有指定任何可能使用的键。然而,key 列显示 PRIMARY,说明实际上使用了主键作为索引。
  • key_len 列值为8,表明在主键上使用了完整的索引长度。对于一个整数类型的主键来说,这通常是正确的。
  • ref 列显示为 NULL,这是因为在这个查询中没有涉及与其他表的关联操作。
  • rows 列显示预计需要读取的行数为10,010。这表明查询将遍历大约10,010个索引项来找到满足条件的数据。
  • Extra 列显示 “Backward index scan”,表示MySQL正在进行反向索引扫描。这通常发生在查询从高到低排序时,或者当查询优化器认为这样做更有效率时。

【根据偏移量查询id】

explain select id from backup_file_5 order by id desc limit 1000,1

在这里插入图片描述
从分析来看,很多指标和【直接分页查询】是一样的,区别是extra值为"Backward index scan; Using index" 表明正在进行反向索引扫描,并且只使用索引,无需回表查询原始数据

【根据偏移 id 来查询数据】

explain select id, backup_source_id, backup_target_id, source_file_path, target_file_path, backup_num, file_type, last_backup_time, file_name, file_suffix, file_length, file_length_after_compress, father_id, is_compress, is_contain_file, create_time, update_time from backup_file_5 where 7373278992159211536 >= id order by id desc limit 10

在这里插入图片描述

  • 查询类型(type)为"range",这意味着MySQL正在执行范围扫描。比全表扫描或全索引扫描要好
  • possible_keys 列显示为空,表示没有指定任何可能使用的键
  • key 列显示 PRIMARY,说明实际上使用了主键作为索引
  • key_len 列值为8,表明在主键上使用了完整的索引长度。对于一个整数类型的主键来说,这通常是正确的
  • ref 列显示为 NULL,这是因为在这个查询中没有涉及与其他表的关联操作
  • rows 列显示预计需要读取的行数为124。这表明查询将遍历大约124个索引项来找到满足条件的数据
  • Extra 列显示 “Using where; Backward index scan”,表示MySQL正在进行反向索引扫描,并应用了WHERE子句中的条件

【总结】

  • 根据偏移量查询id:相对于直接分页查询,只使用 id 来查询,数据量更小,且无需回表操作查询其他字段,消耗的时间和资源少
  • 根据偏移 id 来查询数据:只需要范围扫描,效率更高

总结

  • 查询效率有了比较大的提升
    • 查询第一页,查询时间从5秒下降到ms级别,性能有巨大提升
    • 查询最后一页数据,直接分页查询耗时12.5 秒,改进查询下降到3.4 s,性能提升 3.6 倍
  • 随着数据量的进一步提升,达到千万级,现在的实现方案在查询深分页时性能肯定会非常差,还需要进一步的优化。
  • 其他常用的效率优化逻辑
    • 冷热数据分离:将不常使用的数据迁移到其他数据库中
    • 使用游标分页:记录上一页的最后一条数据id,这样查下一页就很快了,缺点是只能上下页,无法随意切换页

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/438932.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【机器学习】探索GRU:深度学习中门控循环单元的魅力

目录 &#x1f354; GRU介绍 &#x1f354; GRU的内部结构图 2.1 GRU结构分析 2.2 GRU工作原理 2.4 Bi-GRU介绍 2.3 使用Pytorch构建GRU模型 2.5 GRU优缺点 &#x1f354; 小结 学习目标 &#x1f340; 了解GRU内部结构及计算公式. &#x1f340; 掌握Pytorch中GRU工具…

【开源免费】基于SpringBoot+Vue.JS洗衣店订单管理系统(JAVA毕业设计)

本文项目编号 T 068 &#xff0c;文末自助获取源码 \color{red}{T068&#xff0c;文末自助获取源码} T068&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 顾…

【Python】Uvicorn:Python 异步 ASGI 服务器详解

Uvicorn 是一个为 Python 设计的 ASGI&#xff08;异步服务器网关接口&#xff09;Web 服务器。它填补了 Python 在异步框架中缺乏一个最小化低层次服务器/应用接口的空白。Uvicorn 支持 HTTP/1.1 和 WebSockets&#xff0c;是构建现代异步Web应用的强大工具。 ⭕️宇宙起点 &a…

界星空科技漆包线行业称重系统

万界星空科技为漆包线行业提供的称重系统是其MES制造执行系统解决方案中的一个重要组成部分。以下是对该系统的详细介绍&#xff1a; 一、系统概述 万界星空科技漆包线行业称重系统&#xff0c;是集成在MES系统中的一个功能模块&#xff0c;专门用于漆包线生产过程中的重量检…

数据结构-LRU缓存(C语言实现)

遇到困难&#xff0c;不必慌张&#xff0c;正是成长的时候&#xff0c;耐心一点&#xff01; 目录 前言一、题目介绍二、实现过程2.1 实现原理2.2 实现思路2.2.1 双向链表2.2.2 散列表 2.3 代码实现2.3.1 结构定义2.3.2 双向链表操作实现2.3.3 实现散列表的操作2.3.4 内存释放代…

【玩转 JS 函数式编程_006】2.2 小试牛刀:用函数式编程(FP)实现事件只触发一次

文章目录 2.2 该问题的函数式解 A functional solution to our problem1. 高阶函数解 A higher-order solution2. 高阶函数解的手动测试 Testing the solution manually3. 高阶函数解的自动测试 Testing the solution automatically4. 更好的解决方案 Producing an even better…

idea创建springboot模块

1.点击file->新建->model server url&#xff1a;如果倒数第二个java选项没有11&#xff0c;就把这里改为阿里云的 name&#xff1a;模块名字 location&#xff1a;文件存放的位置 其他的根据图片自行填写 2. 3.验证 如果没有iml文件(不影响&#xff0c;可以不弄)&#…

LabVIEW提高开发效率技巧----属性节点优化

在LabVIEW开发中&#xff0c;优化代码的效率和性能是非常重要的&#xff0c;尤其是在涉及前面板控件的属性节点时。频繁使用属性节点可能会导致程序执行速度的明显下降&#xff0c;特别是在处理大量数据或高频率操作时。下面详细介绍一些在LabVIEW开发中优化属性节点使用的技巧…

数据结构--线性表(顺序结构)

1.线性表的定义和基本操作 1.1线性表以及基本逻辑 1.1.1线性表 &#xff08;1&#xff09;n(>0)个数据元素的有限序列&#xff0c;记作&#xff08;a1,a2,...an&#xff09;&#xff0c;其中ai是线性表中的数据元素&#xff0c;n是表的长度。 &#xff08;2&#xff09;…

4个顶级的大模型推理引擎

LLM 在文本生成应用中表现出色&#xff0c;例如具有高理解度和流畅度的聊天和代码完成模型。然而&#xff0c;它们的庞大规模也给推理带来了挑战。基本推理速度很慢&#xff0c;因为 LLM 会逐个生成文本标记&#xff0c;需要对每个下一个标记进行重复调用。随着输入序列的增长&…

ElasticSearch 备考 -- 备份和恢复

一、题目 备份集群下的索引 task&#xff0c;存储快照名称为 snapshot_1 二、思考 这个涉及的是集群的备份&#xff0c;主要是通过创建快照&#xff0c;涉及到以下2步骤 Setp1&#xff1a;注册一个备份 snapshot repository Setp2&#xff1a;创建 snapshot 可以通过两种方…

MindSearch 部署到Github Codespace 和 Hugging Face Space

conda init后需要重开终端&#xff0c;不然一键复制会导致后续pip install会安装错环境 还是报错 ImportError: cannot import name AutoRegister from class_registry (/opt/conda/envs/mindsearch/lib/python3.10/site-packages/class_registry/__init__.py)pip install --…

【技术分析】嘉楠科技SoC芯片K230

概述 K230是嘉楠科技Kendryte系列AIoT芯片中的最新一代SoC芯片&#xff0c;该芯片采用全新的多异构单元加速计算架构&#xff0c;集成的玄铁C908具有2个高能效RISCV计算核心&#xff0c;内置新一代KPU&#xff08;Knowledge Process Unit&#xff09;智能计算单元&#xff0c;…

Unity初识+面板介绍

Unity版本使用 小版本号高&#xff0c;出现bug可能性更小&#xff1b;一台电脑可以安装多个版本的Unity&#xff0c;但是需要安装在不同路径&#xff1b;安装Unity时不能有中文路径&#xff1b;Unity项目路径也不要有中文。 Scene面板 相当于拍电影的片场&#xff0c;Unity程…

Go基础学习11-测试工具gomock和monkey的使用

文章目录 基础回顾MockMock是什么安装gomockMock使用1. 创建user.go源文件2. 使用mockgen生成对应的Mock文件3. 使用mockgen命令生成后在对应包mock下可以查看生成的mock文件4. 编写测试代码5. 运行代码并查看输出 GomonkeyGomonkey优势安装使用对函数进行monkey对结构体中方法…

Chat登录时出现SSO信息出错的解决方法

目录 1. 问题所示2. 问题所示3. 解决方法 1. 问题所示 此贴主要是总结回顾&#xff0c;对此放置在运维专栏 出现如下问题&#xff0c;很懵&#xff0c;以为是节点挂了还是网址蹦了 一直刷新&#xff0c;登录之后就出现这个问题 2. 问题所示 对于SSO&#xff0c;也就是单点登…

深度学习项目----用LSTM模型预测股价(包含LSTM网络简介,代码数据均可下载)

前言 前几天在看论文&#xff0c;打算复现&#xff0c;论文用到了LSTM&#xff0c;故这一篇文章是小编学LSTM模型的学习笔记&#xff1b;LSTM感觉很复杂&#xff0c;但是结合代码构建神经网络&#xff0c;又感觉还行&#xff1b;本次学习的案例数据来源于GitHub&#xff0c;在…

4.4章节python中循环结构得互相嵌套:常用于属于图形(长方形、三角形、菱形)

一、定义和注意事项 在Python中&#xff0c;循环结构&#xff08;如for循环和while循环&#xff09;可以互相嵌套。嵌套循环意味着一个循环内部包含另一个循环。这在处理多维数据或需要执行多次迭代的任务时非常有用。 注意&#xff1a; 1.缩进&#xff1a;在Python中&…

实施威胁暴露管理、降低网络风险暴露的最佳实践

随着传统漏洞管理的发展&#xff0c;TEM 解决了因攻击面扩大和安全工具分散而产生的巨大风险。 主动式 TEM 方法优先考虑风险并与现有安全工具无缝集成&#xff0c;使组织能够在威胁被有效利用之前缓解威胁。 为什么威胁暴露管理 (TEM) 在现代网络安全策略中变得至关重要&…