当前位置: 首页 > news >正文

MySQL知识点讲解

SQL基础

数据库三大范式是什么

  • 第一范式:要求数据库每一列都是不可分割的原子项目。
  • 第二范式:在第一范式的基础上,非码属性必须完全依赖于候选码(在第一范式的基础上消除非主属性对主码的部分函数依赖)。第二范式需要确保数据库表中每一列都和主键相关,而不能和主键的一部分相关。
  • 第三范式:在第二范式的基础上消除传递依赖。确保数据表的每一列数据都和主键直接相关,不能间接相关。

MySQL如何连表查询

  • 内连接:内连接返回两个表中有匹配关系的行
  • 左外连接:返回左表中的所有行,即使在右表中没有匹配的行,未匹配的右表会包含null
  • 右外连接:右外连接返回右表中的所有行
  • 全外连接:全外连接返回两个表中的所有行

Mysql中如何避免重复插入数据

  • 使用UNIQUE约束
  • 使用INSERT.....ON DUPLICATE KEY UPDATE:这个语句允许在插入记录时处理重复键的情况,如果插入的记录和现有的记录冲突,可以选择更新他
  • 使用insert ignore:该语句在插入记录时忽略那些因重复键而导致的插入错误。

Char和VarChar的区别

VarChar后面括号里的数字代表的是字符数,而不是字节数。

int(1)和int(10)在mysql中有什么不同

int(1)和int(10)主要的区别在于显示宽度,不改变存储方式,int固定大小为4字节,所有int占用的存储空间均为4字节,括号内数值为显示的宽度,在特定场景下控制数值展示格式。

唯一作用场景:zerofill补零显示,当字段设置为zerofill时,数字显示时会使用前导零填充至指定宽度。

说一下外键约束

外键约束作用是维护表与表之间的关系,从而确保数据的一致性。

假设我们有一个订单表和支付表,支付表需要获取订单号,但是此时支付表需要获取订单号,此时订单号就是订单表的一个主键,确保了支付表内的每一个订单号都在订单表中存在。如果没有外键,那么此时支付表可能会有不存在于订单表的订单号存在,破坏了数据的一致性和完整性。

MYSQL中的in和exit

in关键字

in用于检查左边的表达式是否存在于右边的列表或者子查询的结果集中,如果存在则返回true,否则返回false

exit关键字

exit用于判断子查询是否至少能返回一行数据,他不关心子查询返回什么数据,只关心子查询是否返回数据,如果子查询有结果,则返回true,没有结果则返回false

区别与选择

  • exit的性能是比in要好的,特别是子查询的表很大时,这是因为exit一旦找到匹配项就会立即停止,而in会扫描整个结果集。
  • null值处理:exit不关心null值,in可以正确处理子查询中的null值的情况。

MySQL查询语句和执行顺序是什么样子的

所有的查询语句都从from开始,每一个步骤都会生成一个虚拟表,这个虚拟表将会作为下一个执行步骤的输入,最后一个产生的虚拟表即为输出结果

存储引擎

执行一条SQL语句的请求过程

  • 连接器:建立连接,管理连接,校验用户身份
  • 查询缓存:若在缓存内命中则直接返回缓存内的数据,否则继续向下执行,mysql8.0已经取消。
  • 解析sql:通过解析器对sql查询语句进行词法分析、语法分析,构建语法树,方便后续模块读取表明、字段、语句类型。
  • 执行sql:执行sql共有三个阶段
    • 预处理阶段检查表或者字段是否存在,将select * 符号扩展为表上所有列
    • 优化阶段:基于查询成本的考虑,选择查询成本最小的执行计划
    • 执行阶段吧:根据执行计划执行sql语句,从粗处引擎读取记录,返回给客户端

讲一下mysq的引擎吧,你有什么了解?

  • InnoDB:InnoDB是mysql的默认存储引擎,具有ACID事物支持、行级锁、外键约束等属性。它适用于高并发的读写操作,支持较好的数据完整性和并发控制。
  • MyISAM:MyISAM是mysql的另一种常见的引擎,具有较低的存储空间和内存消耗,适用于大量的读操作场景。然而,MyISAM不支持事务、行级锁和外键约束,因此在并发写入和数据完整性上有一定限制。
  • Memory:Memory引擎将数据存储在内存中,适用于性能较高的操作,但是在服务器重启或者崩溃时数据会丢失,他不支持事务,行级锁和外键约束

MySQL为什么InnoDB是默认引擎

  • 事务支持:InnoDB引擎提供了对事务的支持,可以进行ACID属性的操作。MyISAM是不支持事务的。
  • 并发性能:innodb引擎采用可行级锁的机制,可以提供更好的并发性能,Myisam存储引擎支持表锁,锁的力度比较大。
  • 崩溃恢复:Innodb引擎通过redolog日志实现了崩溃恢复,可以在数据库发生异常情况时快速恢复。

索引

索引是什么,有什么好处?

索引类似于书籍的目录,可以减少扫描的数量,提高查询效率

  • 如果查询的时候,没有用索引就会全表扫描,这时候查询的时间复杂度是On
  • 如果用到了索引,那么查询的时候,可以基于B+树的二分查找算法,更加高效的进行查询。

索引的分类

  • 按存储结构:B+tree索引、hash索引、full-text索引
  • 按物理存储分类:聚簇索引、二级索引
  • 按字段特性:主键索引、唯一索引、普通索引、前缀索引
  • 按字段个数:单列索引、联合索引。

MySQL中的聚簇索引和非聚簇索引的区别

  • 数据存储:在聚簇索引中,数据行按照索引键值的顺序存储,也就是索引的叶子节点包含了实际的数据行。
  • 由于数据与索引的紧密相连,当通过急促索引查找数据时,可以直接从聚簇索引中获取数据,而不需要额外的查找数据所在的位置。当通过聚簇索引查找数据时,首先在非聚簇索引中找到对应主键值,然后通过这个主键值追溯到对应的数据行
  • 聚簇索引通常是基于主键构建的,每个表只能有一个聚簇索引,因为数据只能有一种物理排序方式,一个表可以有多个非聚簇索引。

如果索引的数据更新,他的存储要不要变化

  • 如果更新的数据是非索引数据,那么他的存储结构是不会变化的
  • 如果更新的是索引数据,那么存储结构是有变化

MySQL主键是聚簇索引嘛

是的,是以聚簇索引的情况存储的。

InnoDB将数据存储在B+树的结构中,其中主键索引的B+树就是所谓的聚簇索引。这意味着表中的数据行在物理上是按照主键的顺序排列的,聚簇索引的叶子节点包含了实际的数据行

InnoDB在创建聚簇索引时,会根据场景选择不同的列

  • 如果有主键,默认使用主键作为聚簇索引的索引键。
  • 如果没有主键,就选择一个不包含null值的唯一列作为索引
  • 在上面都没有的情况下,InnoDB将会生成一个隐式的id作为聚簇索引的索引键

表中十个字段,你主键使用UUID还是自增ID?

自增ID。

因为uuid相对于自增id毫无规律可言,新行的值不一定要比之前的主键值要打,所以innodb无法做到既那总把新行加入到索引的最后,而是需要寻找合适的地方进行插入。

这个过程需要频繁的额外操作,数据的没有顺序会导致数据分布混乱。

MySQL中的索引怎么实现的?

mysql中的innodb引擎采用B+树作为存储结构。

B+树是一种多叉树,叶子结点才存放数据,非叶子结点只存放索引,而且每个结点里的数据是按主键顺序存放的。每一层的父结点的索引值都会出现在下层结点的索引值中,因此在叶子结点中包含了所有的索引值信息,并且每一个叶子结点都有两个指针,分别指向下一个叶子结点和上一个叶子结点。

B+树存储千万级别的操作只需要3-4层即可满足,这意味着从千万级别的表查询数据最多3-4次磁盘io。所以B+数的查询效率很高

查询到数据时,到了B+树的叶子结点之后查找数据该如何做

数据页中的记录按照主键顺序组成单向链表,单向链表的特点就是插入、删除非常方便,到那时检索效率不高,最差情况下需要遍历链表上所有的数据。

因此数据页中有一个页目录,起到记录的索引作用,就和我们的书一样,对每一章都打一个目录。

页目录的创建过程如下:

  1. 将所有的记录划分为几个组,这些记录包括最小记录和最大记录
  2. 每个记录组的最后一条记录就是组内的最大那条记录,并且最后一条记录的头部信息中会存储该组有多少条记录(粉红色字段)
  3. 页目录用来存储每组最后一条记录的地址偏移量,这些偏移量会根据先后顺序存储起来,每组地址的偏移量称之为槽,每个槽相当于指针指向了不同组的最后一个记录

页目录是由多个槽组成的,槽相当于分组记录的索引。因为记录是按照主键的顺序排列的,所以我们查找记录时可以先通过二分法快速定位到在那个槽,然后再遍历槽内的数据(定位到最后一个,B+树的叶子结点是双向链表,可以反推),找到相应的记录。

联合索引的实现原理

将多个字段组合成一个索引,该索引就称之为联合索引

可以看到,联合索引的非叶子结点用两个字段的值作为b+树的key值,当在联合索引查询数据时,先按照product_no字段比较,在product_no相同的情况下,再按照name字段比较。

因此,使用联合索引时,存在最左匹配原则,也就是按照最左优先的方式进行索引的匹配。如果不遵循最左法则,则会导致索引失效。

索引失效原则

六种发生索引失效的原则

  • 当我们使用左右模糊查询的时候,会导致失效
  • 当我们在查询中对索引使用函数
  • 当我们在查询中对索引进行表达式运算
  • mysql在进行字符串和数字比较的时候,会自动把字符串转化为数字,然后进行比较。如果字符串为索引列,但是输入为数字的话,会触发隐式类型转换,然后再进行比较,转换使用cast函数,这就是相当于在索引列上使用了函数
  • 索引列要严格遵循最左前缀法则,否则就会索引失效。
  • 在where子句中,如何or前的条件列是索引列,or后面不是索引列,那么索引会失效。

什么情况下会回表查询

从物理角度看,索引分为聚簇索引、二级索引

其中聚簇索引,存放的是主键+所有的实际数据,但是二级索引只存放主键值。

所以在查询时使用了二级索引,如果查询的数据在二级索引内可以查询的到,那么就不需要回表查询。如果查不到,则需要回道聚簇索引进行回表查询。

什么是覆盖索引

覆盖索引指的是一个索引包含了查询所需要的所有列,因此不需要访问表中的数据行就可以完成查询。

怎么决定建立哪些索引

  • 字段唯一性限制,比如商品编码
  • 可以经常用于where查询条件的字段,这样可以提高整个表的查询速度,如果查询条件不是一个字段,可以建立联合索引
  • 经常用于Group By和Order By的字段,这样在查询的时候就不需要再做一次排序了,因为我们知道在建立好索引后b+树的记录都是排序好的

事务

事务的特性是什么,如何实现的?

  • 原子性:一个事务中的所有操作,要么都全部完成,要不就全部不完成,不会结束在某个中间节点,而事务在执行过程中发生错误,会直接回滚到事务发生前的状态。
  • 一致性:指的是事务操作前和操作后,数据满足完整性约束,数据库保持一致性状态。
  • 隔离性:数据库允许多个并发事务对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时导致的数据不一致。
  • 持久性:事务处理结束后,对数据的修改是永久的,即便系统故障也不会丢失。

mysql 可能出现什么并发相关问题

  • 脏读:如果一个事务读取到了另一个未提交事务修改过的数据,那么这个就是脏读,也即是读到了事务修改前的数据。解释:这里假设有两个事务AB,假设A先读取的数据,并开始了事务,也进行了相对的数据更新(事务并没有提交,也就是说没有持久化,事务A随时可能回滚),但是此时事务B读取了事务A未提交的数据,,假设此时A因为抛出异常而回滚了,此时B读取的就是过期的数据。
  • 不可重复读:在一个事务内多次重复读取同一个数据,出现前后两次读到不一致的问题。解释:假设事务AB,A此时读取了最初态的数据,此时B也读取了最初态的数据,但是此时B运行较快,直接提交了事务,当A再次需要读取时,会发生两次读取数据不一致的问题。
  • 幻读:在一个事务次多次查到符合条件的记录数量不一致,导致幻读。

mysql如何解决并发问题的

  • 锁机制:mysql提供了多种锁保证数据的一致性。包括行级锁、表级锁、页级锁等,通过锁机制,可以在读写操作时对数据进行加锁,确保同一时刻只有一个操作可以操作表。
  • 事务隔离级别:mysql提供了多个事务隔离级别,包括读未提交,读已提交,可以重复读,串行化。选择合适的隔离级别可以防止数据的不一致。
  • MVCC:多版本并发控制,Mysql使用MVCC来管理并发访问,他通过在数据库中保存不同版本信息来实现不同事务之间的隔离。读取数据时,mysql根据事务的隔离级别来选择合适的版本吧。

事务隔离级别都有哪些

  • 读未提交:只一个事务还没提交时,他做的变更就会被其他事务读取到。(可能导致脏读、幻读、不可重复读)
  • 读提交:一个事务提交之后,他做的变更才会被其他的事务看到。(可能导致幻读、不可重复读)
  • 可重复读:指的是事务执行过程中所看到的数据,一直跟这个事务启动时所看到的数据是一致的。Mysql的存储引擎innodb引擎模式就是这个(可能发生幻读)
  • 串行化:对记录加上读写锁,在多个事务对这个记录进行读写操作时,如果发生了冲突,那么就会加锁,后续的事务必须等待这个事务执行完毕才可以执行(都不可能发生)

可重复读情况下,A提交的数据,在事务B可以看见吗

可重复读隔离级别是由MVCC多版本并发控制实现的,实现的方式是开始事务后在执行第一个查询语句后,会创建一个read view,后续的查询语句都会使用这个read view,通过这个read view可以在undo_log版本链中找到事务开始的数据,所以事务过程中查询的数据都是一样的。

串行化隔离级别是基于什么实现的

是通过行级锁来实现的,序列化隔离级别下,普通的select查询是会对记录添加s型的next-key锁,其他事务就没有办法对这些已经加锁的记录进行增删改查操作。避免了脏读、不可重复读和幻读的操作。

介绍下MVCC的实现原理

MVCC允许多个事务同时读取同一行数据,而不会彼此堵塞,每个事务看到的数据版本是该事务开始时的数据版本。这意味着,如果此时其他事务期间修改了数据,正在运行的事务仍然看到的是他开始的状态。

对于读提交和可重复读隔离级别事务来说,他们是通过read view来实现的,他们的区别在于创建read view的时机不同

  • 读提交是在每个select语句执行前都会生成一个read view
  • 可重复读是在第一次select后生成一个read view,然后整个事务期间都使用这个read view

Read view的四个字段

对于使用innodb存储引擎的数据库表,他的聚簇索引记录中都包含下面两个隐藏字段

trx_id,当一个事务对某条聚簇索引记录进行改动时,就会将该事务的事务id记录在trx_id列内。

roll_pointer:每次对某条索引记录进行更改时,都会把旧版本的记录写入到undo_log内,然后通过高roll_pointer指向这个旧版本,以便于及时回退。

在穿件read_view后,我们可以将记录中的trx_id划分为这三种情况

一个事务去访问记录的时候,除了自己的更新记录总是可见之外,还有几种情况

  • 如果记录的trx_id的值小于read_view中的min_trx_id的值,表示这个版本的记录在创建read view前就已经提交的事务生成的,所以该版本的记录对当前事务可见
  • 如果记录的trx_id的值大于read_view中的min_trx_id,表示这个版本的记录在创建read view之后才启动生成的,所以该版本不可见
  • 如果trx_id在最大最小值之间,需要判断trx_id是否在m_ids列表中
  • 如果trx_id在m_ids列表中,则表示该版本的活跃事务仍然活跃,还未进行提交,所以该版本不可见
  • 如果不在,则表示已经提交,则可以看见。

讲一下mysql中的锁

  • 全局锁:通过flush tables with read lock语句将会将整个数据库处于只读状态。这时其他线程执行所有的修改/增加操作都会被阻塞。全局锁住要应用于全库逻辑备份,这样在备份数据库期间,不会因为数据或者表结构的变化出现备份文件的数据与预期不一致的情况。
  • 表级锁:
    • 表锁:通过lock tables语句可以对表进行加锁,表锁除了会限制别的线程的读写,也会限制本线程的读写。
    • 元数据锁:当我们对这个表进行操作时,会自动给这个表添加MDL,对一张表的CRUD操作时,添加的是MDL读锁,对一张表结构进行变更操作时,添加的是MDL写锁,MDL是保证当前用户对表执行CRUD操作时,防止其他线程对这个表结构更改。
    • 意向锁:当执行插入、更新、删除操作,需要对表加上意向独占锁,然后对记录加锁,意向锁的目的是快速判断表内是否有记录被加锁
  • 行级锁:innoDB支持行级锁。

数据库内的行级锁和表级锁都有什么作用

表锁的作用:

  • 整体控制:表锁可以控制整个表的并发访问,当一个事务获取了表锁时,其他事务无法访问对该表的任何读写操作,从而确保了数据的一致性
  • 粒度大:表锁的粒度相对较大,在锁定表的情况下,从而会影响到表的其他操作
  • 使用大批量操作:表锁适用于需要大批量操作的场景,例如表的重建、大数据量的加载/插入等

如果两个update语句同时处理同一条数据,会不会阻塞

会的,因为InnoDB引擎默认是实现了行级锁,当对同一数据进行修改时,如果此时已经有一个线程在更新数据,另一个线程就需要阻塞等待

日志

mysql中都有什么日志

  • redo_log:重做日志,是innodb存储引擎层生成的日志,实现了事务中的持久性,用于掉电恢复等故障
  • undo_log:是存储引擎层生成的日志,实现了事务的原子性,用于事务回退和MVCC
  • bin_log:是server层生成的日志,用于数据备份和主从复制
  • relay log:中继日志,用于主从复制场景下
  • 慢查询日志:用于执行时间长的sql,需要设置设置阈值后手动开启

讲一下bin_log

Mysql在完成一条更新后,server会生成一个bin log,等之后事务提交的时候,会将该事务执行过程中产生的所有的binlog统一写入binlog文件,binlog是server实现的日志,所有的存储引擎都可以使用。

binlog是追加写,写满一个文件就会创建一个新的文件继续写,不会覆盖以前的日志,保存的是全量日志,用于备份恢复,主从复制。binlog会记录所有数据表结构变更和表数据修改的日志

3种模式

  • statement:每一条修改数据都SQL语句都会被写入到binlog,相当于记录了逻辑操作,所以针对这种格式,binlog可以称为逻辑日志。主从复制种上slave端再根据sql语句重现。但是statement由动态函数问题,比如now和uuid函数会导致这个问题。
  • row:记录行最终被修改为什么样子了,相当于记录了一个行,就不能称之为逻辑日志了,但是row的缺点就是每行数据都会被记录,一个批量操作的每行都会被记录,导致binlog体积过大。
  • mixed:包含了statement和row的模式,根据不同情况自动使用row和statement。

undo_log的作用

undo log是一种撤销回退的日志,他保证了事务的ACID特性中的原子性。

当事务没有提交之前,Mysql会将更新前的数据更新到undo log日志内,当事务回滚时可以利用undo log日志来回滚。在发生回滚时,就读取undo log内的数据,然后做原先相反的操作。

有了undo log为什么还要使用redolog

Buffer Pool确实是提高了读写速度,但是问题是,Buffer Pool是基于内存的,而内存的可靠性堪忧,一旦掉电,数据会全部丢失。

为了防止断电导致丢失数据的问题,当有一条数据需要更新的时候,InnoDB引擎就会先更新内存(同时标记为脏页),然后将本地对整个页面的修改以redo log的方式存储起来,这就算更新完成了。

后续,InnoDB引擎会在适当的时候,由后台线程将存储在Buffer Pool的脏页刷新到内存内,这就是WAL技术。(修改的信息不会立刻写在磁盘上,而是先写进日志,然后在合适的时间内写入磁盘),而这里采用redo log是防止mysql服务器掉电瘫痪导致存在内存没来得及更新的数据,保证了数据的持久性。

还有一种情况,因为redo log采用了追加操作,所以在向磁盘内写入时,是以顺序的形式进行写入的,效率比直接写入磁盘更加高(直接写入磁盘需要先找到位置,然后才会写入,直接写入为随机写)

可不可以只用binlog不用redo log

不呢binlog为server层日志,无法记录系统底层细节,比如还有哪些数据没刷盘等,这样崩溃恢复的时候会特别麻烦。

Update语句执行的流程

update user set name = 'test' where id = 1;

按照上述语句来阐述一下Mysql的执行流程。

首先,查询id=1的记录所在的数据页是否在buffer pool中,如果在就直接给执行器执行,不在的话需要从执行器更新。

执行器得到索引记录后,会查看更新后的记录和更新前的记录是否一致,如果一致则不进行任何操作,不一致则交给innndb进行操作。

innodb开启事务,在进行更新前首先记录这个记录的undo_log,因为这是更新操作,需要把被更新的旧值记录下来。undolog会进入Buffer Pool的undo页面。随后innodb开始更新记录,首先更新内存,并把这一页标记为脏页,并写入redo log

但是此时innodb并没有把记录直接写进磁盘,inndb会在事务提交后寻找一个合适的时机将脏页面写入磁盘。这就是WAL技术。

随后,语句彻底更新完成后,随后就会在server层更新binlog日志,此时记录的binlog会被写入binlog cache,但是并没有提交到磁盘上

事务提交

prepare:将redo log对应的事务设置为prepare,然后将redo log刷新到硬盘

commit:将binlog刷新到磁盘,接着调用引擎的接口,将redolog的状态设置为commit。

性能优化

给你一张表,发现查询效率特别低,有哪些方案

  • 使用explain分析:使用explian语句分析SQL语句的执行计划,找出慢查询的原因,比如是否使用了全表扫描,是否是有索引没有被使用的情况,并根据相对的情况对索引进行适当修改。
  • 创建或优化索引:根据查询条件适当的优化索引,特别是经常使用where去查询的,如果数据表中经常有多个条件字段,可以考虑创建多个索引
  • 避免索引失效
  • 查询优化:尽量少的使用select *,填写真正需要查询的列,尽量不要连表查询,不得已情况下尽量使用小表去驱动大表
  • 优化数据表:如果单表数据量超过了千万级别,可以考虑进行分库分表,减轻单个表的压力,也可以将字段多的表拆为多个表。
  • 使用缓存:使用redis等分布式缓存组件,缓存热点数据,避免请求直达数据库。

架构设计

MySQL主从复制了解吗

MySQL的主从复制住要依赖于binlog,将Mysql上的所有变化以二进制的形式保存磁盘上,复制过程就是将binlog的数据从主库复制到从库

这个过程是异步的,也就是主库上执行事务操作的线程不会等到复制binlog同步线程的完成。因为更新时间不确定,所以可能导致主从复制的延迟问题。要解决这个问题,唯一的办法就是对于大事务、实时性要求高的操作直接放到主库上执行,避免延迟导致的数据错乱。

分库分表是什么?有什么区别

  • 分库:分库是一种水平扩展数据库的方案,将数据按照一定规则划分为多个独立的数据库中,每个数据库只负责存储部分数据,实现了数据的拆分和分布式存储片,分库主要为了解决并发连接过多。
  • 分表:分表是当一个单表的数据量过大,将一个单表分为多个表,一个表只存储一部分数据。这种可以提高查询效率,减轻单个表的压力,分表主要是解决单表数据量过大,导致查询性能下降的问题。

分库分表的形式:

  • 垂直分库:按照业务和功能进行拆分,将不同业务的数据分别放到不同的数据库中,核心概念就是专库专用。
  • 垂直分表:针对业务上字段比较多的大表进行的,一般是把业务宽表中的比较独立的字段或者不常用的字段拆分到单独的数据表中,是一种大表拆小表的形式。
  • 水平分库:把同一个表按照一定规则拆分到不同数据库中,每个库可以位于不同的服务器上,以实现水平的扩展,是一种提升数据库性能的方式。
  • 水平分表:在同一个数据库内,把一张大表按照一定规则拆分为多个结构相同的表,每个表只存储一部分数据,但是这只是解决了单表数据量过大的问题,性能没有显著提升。要是想进一步提升性能,就需要将不同的表散布到不同数据库中,实现分布式的效果。

相关文章:

  • 【软件工程】软件测试基础知识
  • MYDB仿MySQL手写数据库项目总结
  • 【Maven】项目管理工具
  • 深度学习-全连接神经网络-2
  • Rust: 从内存地址信息看内存布局
  • 问题 | RAIM + LSTM 你怎么看???
  • Day5-UFS总结
  • WPS科大讯飞定制版 11.4.1.5| 无广告,省电和降低占用,可与普通版本共存
  • stm32week12
  • 如何在量子计算时代保障 Sui 的安全性
  • (14)VTK C++开发示例 --- 将点投影到平面上
  • 中通 Redis 集群从 VM 迁移至 PVE:技术差异、PVE 优劣势及应用场景深度解析
  • 【GIT】为什么要变基下拉,变基下拉失败,提示没有暂存如何解决?
  • 使用QEMU(8.2.10)调试ARM64 Linux内核6.6.30
  • 【STM32单片机】#10.5 串口数据包
  • 50道SQL经典练习题
  • 如何通过API获取淘宝评论?实战讲解
  • JVM面试题学习
  • JumpServer多用户VNC桌面配置指南:实现多端口远程访问
  • 互联网大厂Java面试:Spring Cloud与微服务的奇妙之旅
  • 世界史圆桌|16-18世纪的跨太平洋贸易
  • 从 “负分” 到世界杯亚军,蒯曼专打“逆风局”
  • 美方因涉港问题对中国官员滥施非法单边制裁,外交部:强烈谴责,对等反制
  • 特朗普亲自介入美日关税谈判:以势压人还是给对手“送助攻”
  • 新城市志|全球供应链动荡加剧,中国稳外贸有信心有底气
  • 纪念沈渭滨︱志于道而游曳于士和氓间的晚年沈先生