MYSQL基础架构、执行过程分析、事务的实现、索引的选择、覆盖索引

news2024/11/23 20:54:40

本文是mysql45讲的1-5的总结

文章目录

  • 基础架构
    • 连接器
    • 分析器
    • 优化器
    • 执行器
    • SQL查询执行过程
      • 详细执行步骤
    • SQL更新执行过程
    • 重要的日志模块:redo log
    • 重要的日志模块:binlog
      • 阶段性提交
  • 事务
    • 事务隔离的实现
    • 启动
  • 索引
    • 数据库索引模型
    • InnoDB索引组织结构
    • 主键选择
    • B+树维护操作
    • 索引重建问题
  • 覆盖索引
    • 最左前缀原则
    • 索引下推
      • 策略选择和权衡
      • 建议

基础架构

先来看一张图:

basic structure

MySQL分为Server层和存储引擎层两部分。

Server层:连接器、查询缓存、分析器、优化器、执行器等,涵盖MySQL的大多数核心服务功能,以及所有的内置函数(如日期、时间、数学和加密函数等),所有跨存储引擎的功能都在这一层实现,比如存储过程、触发器、视图等。

而存储引擎层负责数据的存储和提取。其架构模式是插件式的,支持InnoDB、MyISAM、Memory等多个存储引擎。现在最常用的存储引擎是InnoDB,它从MySQL 5.5.5版本开始成为了默认存储引擎。

不同存储引擎的表数据存取方式不同,支持的功能也不同

从图中不难看出,不同的存储引擎共用一个Server层,也就是从连接器到执行器的部分。

连接器

顾名思义就是负责跟客户端建立连接、获取权限、维持和管理连接的

我们通常命令行会这么写:

mysql -h$ip -P$port -u$user -p

用户的权限是在登录时就确认好的, 也就是说如果在登录过程中对当前用户的权限进行了修改,当前已登录用户的权限并不会发生改变,直到用户再次登录,权限才会更新

我们可以通过

show processlist

对当前链接用户进行查看

客户端如果太长时间没动静,连接器就会自动将它断开。这个时间是由参数wait_timeout控制的,默认值是8小时。

如果在连接被断开之后,客户端再次发送请求的话,就会收到一个错误提醒: Lost connection to MySQL server during query。这时候如果你要继续,就需要重连,然后再执行请求了。

数据库里面,长连接是指连接成功后,如果客户端持续有请求,则一直使用同一个连接。短连接则是指每次执行完很少的几次查询就断开连接,下次查询再重新建立一个。

建立连接的过程通常是比较复杂的,所以我建议你在使用中要尽量减少建立连接的动作,也就是尽量使用长连接。

分析器

作用:语句词法分析

语法分析器会根据语法规则,判断你输入的这个SQL语句是否满足MySQL语法。

如果你的语句不对,就会收到“You have an error in your SQL syntax”的错误提醒,比如下面这个语句select少打了开头的字母“s”。

mysql> elect * from t where ID=1;

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from t where ID=1' at line 1

优化器

在真正执行之前还需要一个优化,比如说当表里面有多个索引的时候,有多个join的时候,谁先谁后,这就是优化器要决定的事情,如何使用让效率变得更高

执行器

分析器知道了要怎么做,优化器知道了该怎么做,于是开始执行;

执行优化器选择的执行计划,与存储引擎协同工作,完成数据的实际检索和修改。

执行器会先查看是否有表读取权限,如果有权限,就打开表继续执行。打开表的时候,执行器就会根据表的引擎定义,去使用这个引擎提供的接口。

SQL查询执行过程

  • 查询示例select * from T where ID=10;
    • 输入:用户输入的SQL查询语句。
    • 输出:查询结果。

详细执行步骤

  1. SQL解析

    • 词法分析:将SQL语句分解成有意义的元素(词法单元),如关键字、标识符、常量。
    • 语法分析:根据MySQL的语法规则验证词法单元的结合是否正确。
  2. 查询优化

    • 执行计划生成:优化器评估多种可能的查询路径,生成多个执行计划。
    • 成本估算:为每个执行计划估算执行成本,选择成本最低的计划。
  3. 查询执行

    • 执行器与存储引擎交互:执行器指挥存储引擎按照优化后的计划执行查询。
    • 数据检索:存储引擎从数据文件中检索数据,返回给执行器。

    SQL更新执行过程

    更新里面其实就是查询+修改

    MySQL可以恢复到半个月内任意一秒的状态,那是怎么做到的?

    与查询流程不一样的是,更新流程还涉及两个重要的日志模块,它们正是我们今天要讨论的主角:redo log(重做日志)和 binlog(归档日志)。

    重要的日志模块:redo log

    其实就是MySQL里经常说到的WAL技术,WAL的全称是Write-Ahead Logging,它的关键点就是先写日志,再写磁盘,也就是先写粉板,等不忙的时候再写账本。

    具体来说,当有一条记录需要更新的时候,InnoDB引擎就会先把记录写到redo log(粉板)里面,并更新内存,这个时候更新就算完成了。同时,InnoDB引擎会在适当的时候,将这个操作记录更新到磁盘里面

    InnoDB的redo log是固定大小的,比如可以配置为一组4个文件,每个文件的大小是1GB,那么这块“粉板”总共就可以记录4GB的操作。从头开始写,写到末尾就又回到开头循环写,如下面这个图所示。

    redo_log

    write pos是当前记录的位置,一边写一边后移,写到第3号文件末尾后就回到0号文件开头。checkpoint是当前要擦除的位置,也是往后推移并且循环的,擦除记录前要把记录更新到数据文件。

    write pos和checkpoint之间的是“粉板”上还空着的部分,可以用来记录新的操作。如果write pos追上checkpoint,表示“粉板”满了,这时候不能再执行新的更新,得停下来先擦掉一些记录,把checkpoint推进一下。

    有了redo log,InnoDB就可以保证即使数据库发生异常重启,之前提交的记录都不会丢失,这个能力称为crash-safe

    要理解crash-safe这个概念,可以想想我们前面赊账记录的例子。只要赊账记录记在了粉板上或写在了账本上,之后即使掌柜忘记了,比如突然停业几天,恢复生意后依然可以通过账本和粉板上的数据明确赊账账目。

    重要的日志模块:binlog

    Server层也有自己的日志,称为binlog(归档日志)

    因为最开始MySQL里并没有InnoDB引擎。MySQL自带的引擎是MyISAM,但是MyISAM没有crash-safe的能力,binlog日志只能用于归档。而InnoDB是另一个公司以插件形式引入MySQL的,既然只依靠binlog是没有crash-safe能力的,所以InnoDB使用另外一套日志系统——也就是redo log来实现crash-safe能力。

    这两种日志有以下三点不同。

    1. redo log是InnoDB引擎特有的;binlog是MySQL的Server层实现的,所有引擎都可以使用。
    2. redo log是物理日志,记录的是“在某个数据页上做了什么修改”;binlog是逻辑日志,记录的是这个语句的原始逻辑,比如“给ID=2这一行的c字段加1 ”。
    3. redo log是循环写的,空间固定会用完;binlog是可以追加写入的。“追加写”是指binlog文件写到一定大小后会切换到下一个,并不会覆盖以前的日志。

    更新过程

    1. 执行器先找引擎取ID=2这一行。ID是主键,引擎直接用树搜索找到这一行。如果ID=2这一行所在的数据页本来就在内存中,就直接返回给执行器;否则,需要先从磁盘读入内存,然后再返回。
    2. 执行器拿到引擎给的行数据,把这个值加上1,比如原来是N,现在就是N+1,得到新的一行数据,再调用引擎接口写入这行新数据。
    3. 引擎将这行新数据更新到内存中,同时将这个更新操作记录到redo log里面,此时redo log处于prepare状态。然后告知执行器执行完成了,随时可以提交事务。
    4. 执行器生成这个操作的binlog,并把binlog写入磁盘。
    5. 执行器调用引擎的提交事务接口,引擎把刚刚写入的redo log改成提交(commit)状态,更新完成。

    更新过程

    阶段性提交

    最后三步看上去有点“绕”,将redo log的写入拆成了两个步骤:prepare和commit,这就是"两阶段提交”

    binlog会记录所有的逻辑操作,并且是采用“追加写”的形式。如果你的DBA承诺说半个月内可以恢复,那么备份系统中一定会保存最近半个月的所有binlog,同时系统会定期做整库备份。这里的“定期”取决于系统的重要性,可以是一天一备,也可以是一周一备。

    当需要恢复到指定的某一秒时,比如某天下午两点发现中午十二点有一次误删表,需要找回数据,那你可以这么做:

    • 首先,找到最近的一次全量备份,如果你运气好,可能就是昨天晚上的一个备份,从这个备份恢复到临时库;
    • 然后,从备份的时间点开始,将备份的binlog依次取出来,重放到中午误删表之前的那个时刻。

    这样你的临时库就跟误删之前的线上库一样了,然后你可以把表数据从临时库取出来,按需要恢复到线上库去。

    为什么日志需要“两阶段提交”。这里不妨用反证法来进行解释。

    由于redo log和binlog是两个独立的逻辑,如果不用两阶段提交,要么就是先写完redo log再写binlog,或者采用反过来的顺序。我们看看这两种方式会有什么问题。

    仍然用前面的update语句来做例子。假设当前ID=2的行,字段c的值是0,再假设执行update语句过程中在写完第一个日志后,第二个日志还没有写完期间发生了crash,会出现什么情况呢?

    1. 先写redo log后写binlog。假设在redo log写完,binlog还没有写完的时候,MySQL进程异常重启。由于我们前面说过的,redo log写完之后,系统即使崩溃,仍然能够把数据恢复回来,所以恢复后这一行c的值是1。

      但是由于binlog没写完就crash了,这时候binlog里面就没有记录这个语句。因此,之后备份日志的时候,存起来的binlog里面就没有这条语句。

      然后你会发现,如果需要用这个binlog来恢复临时库的话,由于这个语句的binlog丢失,这个临时库就会少了这一次更新,恢复出来的这一行c的值就是0,与原库的值不同。

    2. 先写binlog后写redo log。如果在binlog写完之后crash,由于redo log还没写,崩溃恢复以后这个事务无效,所以这一行c的值是0。但是binlog里面已经记录了“把c从0改成1”这个日志。所以,在之后用binlog来恢复的时候就多了一个事务出来,恢复出来的这一行c的值就是1,与原库的值不同。

    可以看到,如果不使用“两阶段提交”,那么数据库的状态就有可能和用它的日志恢复出来的库的状态不一致。

    不只是误操作后需要用这个过程来恢复数据。当你需要扩容的时候,也就是需要再多搭建一些备库来增加系统的读能力的时候,现在常见的做法也是用全量备份加上应用binlog来实现的,这个“不一致”就会导致你的线上出现主从数据库不一致的情况。

    简单说,redo log和binlog都可以用于表示事务的提交状态,而两阶段提交就是让这两个状态保持逻辑上的一致。

    事务

    当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。

    隔离得越严实,效率就会越低。因此我们在二者之间寻找一个平衡点。

    SQL标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable ):

    • 读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
    • 读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
    • 可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
    • 串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

    Oracle数据库的默认隔离级别其实就是“读提交”,因此对于一些从Oracle迁移到MySQL的应用,为保证数据库隔离级别的一致,你一定要记得将MySQL的隔离级别设置为“读提交”。

    事务隔离的实现

    在MySQL中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。

    假设一个值从1被按顺序改成了2、3、4,在回滚日志里面就会有类似下面的记录:

    ,不同时刻启动的事务会有不同的read-view。如图中看到的,在视图A、B、C里面,这一个记录的值分别是1、2、4,同一条记录在系统中可以存在多个版本,就是数据库的多版本并发控制(MVCC)。对于read-view A,要得到1,就必须将当前值依次执行图中所有的回滚操作得到。

    回滚日志会当系统里没有比这个回滚日志更早的read-view的时候被删除

    为什么不要用长事务

    1. 长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。
    2. 长事务还占用锁资源,也可能拖垮整个库

启动

MySQL的事务启动方式有以下几种:

  1. 显式启动事务语句, begin 或 start transaction。配套的提交语句是commit,回滚语句是rollback。
  2. set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个select语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行commit 或 rollback 语句,或者断开连接。

有些客户端连接框架会默认连接成功后先执行一个set autocommit=0的命令。这就导致接下来的查询都在事务中,如果是长连接,就导致了意外的长事务。

因此,我会建议你总是使用set autocommit=1, 通过显式语句的方式来启动事务。

但是有的开发同学会纠结“多一次交互”的问题。对于一个需要频繁使用事务的业务,第二种方式每个事务在开始时都不需要主动执行一次 “begin”,减少了语句的交互次数。如果你也有这个顾虑,我建议你使用commit work and chain语法。

在autocommit为1的情况下,用begin显式启动的事务,如果执行commit则提交事务。如果执行 commit work and chain,则是提交事务并自动启动下一个事务,这样也省去了再次执行begin语句的开销。同时带来的好处是从程序开发的角度明确地知道每个语句是否处于事务中。

你可以在information_schema库的innodb_trx这个表中查询长事务,比如下面这个语句,用于查找持续时间超过60s的事务。

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60

索引

数据库索引模型

  1. 哈希表
    • 适用于等值查询,比如Memcached及其他一些NoSQL引擎
    • 查询效率高,但不支持范围查询
    • 插入删除效率低,可能会出现哈希冲突
  2. 有序数组
    • 在等值查询和范围查询场景中的性能就都非常优秀
    • 查询效率高
    • 插入删除效率低,需要移动数据
    • 有序数组索引只适用于静态存储引擎
  3. B+树
    • InnoDB采用B+树作为索引模型
    • 支持等值查询和范围查询
    • 查询效率高,插入删除效率也较高

InnoDB索引组织结构

example

从图中不难看出,根据叶子节点的内容,索引类型分为主键索引和非主键索引。

主键索引的叶子节点存的是整行数据。在InnoDB里,主键索引也被称为聚簇索引(clustered index)。

非主键索引的叶子节点内容是主键的值。在InnoDB里,非主键索引也被称为二级索引(secondary index)。

  1. 主键索引对应聚集索引
    • 数据按主键物理顺序存储;主键查询只需要搜索B+树就行
  2. 辅助索引的叶子节点为主键值
    • 通过主键索引查找数据,普通索引需要先搜索引树得到ID的值,在到ID索引树搜索,称为回表操作;

也就是说,基于非主键索引的查询需要多扫描一棵索引树。因此,我们在应用中应该尽量使用主键查询

主键选择

  1. 自增主键
    • 插入顺序,不会触发分裂
    • 空间占用小
  2. 业务主键
    • 更符合实际需求
    • 也可以直接作为主键索引

B+树维护操作

  1. 插入如果导致页满,需要分裂页
  2. 删除如果导致页利用率低,需要合并页

索引重建问题

  1. 直接使用ALTER TABLE效率可能不高
  2. 应考虑使用线上DDL或备份还原方式

显然,主键长度越小,普通索引的叶子节点就越小,普通索引占用的空间也就越小。

所以,从性能和存储空间方面考量,自增主键往往是更合理的选择。

有没有什么场景适合用业务字段直接做主键的呢?还是有的。比如,有些业务的场景需求是这样的:

  1. 只有一个索引;
  2. 该索引必须是唯一索引。

覆盖索引

  • 定义:如果一个索引包含了查询所需的所有字段,则称为覆盖索引。
  • 优点:能够减少数据库访问成本,因为可以直接在索引中获取数据,无需回表到主数据文件。
  • 应用:例如,在查询 SELECT ID FROM T WHERE k BETWEEN 3 AND 5 中,如果索引 k 已经包括 ID 字段,则此索引覆盖了查询需求。

最左前缀原则

  • 定义:在使用复合索引时,查询条件可以使用索引的最左边的一个或多个字段来优化查询。
  • 优点:使得数据库能够利用索引快速定位数据,减少扫描范围。
  • 实例:在联合索引 (name, age) 中,查询可以利用 namenameage 的组合来加速,但不能只用 age

索引下推

 无索引下推执行流程

索引下推执行流程

  • 定义:MySQL 5.6及以上版本的优化技术,允许在索引层面过滤数据,而不是在找到完整记录后才进行过滤。
  • 优点:减少了不必要的数据加载和回表操作,提高查询效率。
  • 示例:在 name, age 索引中,查询 SELECT * FROM tuser WHERE name LIKE '张%' AND age = 10 可以直接在索引层过滤掉不符合 age 条件的记录。

策略选择和权衡

  • 联合索引的选择:在创建联合索引时,应考虑查询模式以及字段在查询中的频率和顺序。正确的字段顺序可以减少冗余索引,优化存储和维护成本。
  • 索引的成本:尽管索引可以提高查询性能,但它们也会增加写操作的负担,并占用额外的存储空间。因此,在添加索引前需要权衡其对性能的潜在影响。

建议

  • 覆盖索引使用建议:对于高频查询特别是在只需要表中少数几个字段的情况下,考虑使用覆盖索引。
  • 索引审查:定期审查现有索引的效能和必要性,移除不再有效或重复的索引,优化索引配置

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

电源小白入门学习7——USB充电、供电、电源路径管理

电源小白入门学习7——USB充电、供电、电源路径管理 USB充电系统需要考虑的因素开关充电和线性充电充电路径管理输入限流路径管理(动态功率管理)理想二极管帮助提高电池利用率输入过充抑制 上期我们介绍了锂离子电池的电池特性,及充电电路设计…

字节跳动(社招)三面算法原题

TikTok 喘息 继上月通过强制剥离 TikTok 法案后,美国众议院在当地时间 20 日下午以 360 票赞成 58 票反对通过了新的法案:剥离 TikTok 的期限由生效后 165 天调整至 270 天之内,即今年 11 月的美国总统大选后。 之前我们讲过,TikT…

[安全开发]如何搭建一款自己的网安微信机器人

前言 hxd写的一个微信网安机器人。 原理 基于HOOK的微信机器人,以往的机器人大多数为协议机器人,封号概率极大(下面会详细讲解hook和协议的区别),而HOOK机制的大大减小了封号几率。 什么是协议机器人? …

腾讯云服务器产品特惠集合

腾讯云服务器近期推出了多项特惠活动,以满足不同用户的需求。以下是一些主要的特惠信息: 特惠产品合集页 精选特惠 用云无忧 腾讯云提供了极具竞争力的价格。例如,用户可以找到2核2G3M配置的云服务器,月费低至5.08元;…

【C++之map的应用】

C学习笔记---021 C之map的应用1、map的简单介绍1.1、基本概念1.2、map基本特性 2、map的基本操作2.1、插入元素2.2、访问元素2.3、删除元素2.4、遍历map2.5、检查元素是否存在2.6、获取map的大小2.7、清空map2.8、基本样例 3、map的基础模拟实现4、测试用例4.1、插入和遍历4.2、…

Python查询PostgreSQL数据库

哈喽,大家好,我是木头左! Python与PostgreSQL的连接 需要了解如何在Python中连接到PostgreSQL数据库。这通常涉及到使用一个库,如psycopg2,它是Python中用于PostgreSQL的最流行的适配器。安装psycopg2非常简单&#x…

[Java EE] 多线程(八):CAS问题与JUC包

🌸个人主页:https://blog.csdn.net/2301_80050796?spm1000.2115.3001.5343 🏵️热门专栏:🍕 Collection与数据结构 (90平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm1001.2014.3001.5482 🧀Java …

用 Go map 要注意这个细节,避免依赖他!

有的小伙伴没留意过 Go map 输出、遍历顺序,以为它是稳定的有序的,会在业务程序中直接依赖这个结果集顺序,结果栽了个大跟头,吃了线上 BUG。 有的小伙伴知道是无序的,但却不知道为什么,有的却理解错误? 今…

Flutter笔记:Widgets Easier组件库 - 使用标签(Tag)

Flutter笔记 Widgets Easier组件库 - 使用标签(Tag) - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite:http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this …

滑动窗口 | 1652. 拆炸弹 |LeetCode

文章目录 题目介绍暴力(可以过力扣竟然。不愧是简单题):滑动窗口 祝你天天开心 题目介绍 你有一个炸弹需要拆除,时间紧迫!你的情报员会给你一个长度为 n 的 循环 数组 code 以及一个密钥 k 。 为了获得正确的密码,你需要替换掉每…

【嵌入式笔试题】进程线程笔试题

非常经典的笔试题。 1.进程&线程(16道) 1.1异步IO和同步IO区别? 答案:如果是同步IO,当一个IO操作执行时,应用程序必须等待,直到此IO执行完。 相反,异步IO操作在后台运行,IO操作和应用程序可以同时运行,提高系统性能,提 高IO流量。 解读:在同步文件IO中,线…

IntelliJ IDEA 2024 for Mac:Java开发者的强大助手

IntelliJ IDEA 2024 for Mac是Java开发者不可或缺的强大助手,它凭借卓越的性能和丰富的功能,赢得了广大开发者的青睐。 作为集成开发环境(IDE)的佼佼者,IDEA 2024提供了全面的代码编辑和智能提示功能。它不仅能实时分析…

视频素材哪个软件好用?8个短视频素材高清无水印

在今日这个视觉表现至关重要的时代,获取合适的视频素材成为制作任何类型视频内容的基石。从企业宣传片到社交媒体短视频,高质量的视频素材能够显著提升内容的吸引力和专业度。这里列出了一些全球顶尖的视频素材平台,每一个都能为您的视频项目…

高效转化,智能私信软件策略揭秘

在数字营销的浪潮中,智能私信软件策略正成为提升转化率的重要工具。这种软件以其个性化、自动化的特点,正在重新定义与客户的互动方式,让企业能够更加高效地吸引并留住潜在客户。 智能私信软件的核心在于其高度的定制化和人性化设计。通过大数…

CasaOS玩客云安装memos开源云笔记并实现随时随地远程记笔记

文章目录 前言1. 使用Docker部署memos2. 注册账号与简单操作演示3. 安装cpolar内网穿透4. 创建公网地址5. 创建固定公网地址 前言 本文主要介绍如何在CasaOS玩客云,使用Docker本地部署21.6K stars的热门开源云笔记服务memos,并结合cpolar内网穿透工具打…

Llama3-Tutorial之XTuner微调Llama3个人小助手

Llama3-Tutorial之XTuner微调Llama3个人小助手 使用XTuner微调llama3模型。 参考: https://github.com/SmartFlowAI/Llama3-Tutorial 1. web demo部署 参考上一节内容已经完成web demo部署,进行对话测试, 当前回答基于llama3官方发布的模型进行推理生成&…

HCIP-Datacom-ARST必选题库_BGP【道题】

1.关于summary automatic命令和BGP聚合的描述,错误的是? 该命令用于实现自动聚合,其优先级高于手动聚合 配置该命令后,BGP将按自然网段聚合路由 该命令用来使能对本地引入的路由进行自动聚合 配置该命令后,BGP只向对等体发送聚合后的路由 1.关于summary automatic命令和BGP聚…

基于51单片机的手动数字时钟设计

基于51单片机的手动数字时钟 (仿真+程序) 功能介绍 具体功能: 1.八位数码管显示时分秒,格式为XX-XX-XX; 2.六个按键控制时、分、秒的加减; 3.复位按键重新计时; ​演示视频&am…

文件加密软件排行榜前五:好用的文件加密软件推荐

后台有很多老板留言,说最近机密数据外泄的事情频发,让自己开始有了危机意识,想要提前针对企业安全问题采取措施,比方说选一款适合防泄密软件,但是不知道如何选择。 下面介绍几款软件,让大家了解一下市面上常…

Python中的函数定义(def)详解

Python中的函数定义(def)详解 在编程语言中,函数是组织代码的一种方式,它们可以帮助我们将复杂的程序拆分为简单、易管理的部分。在Python中,函数的定义使用def关键字。 什么是函数? 函数是一段完成特定…