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

Java八股—MySQL

1、索引失效的场景

索引失效的场景是指在数据库查询中,虽然我们为某些字段建立了索引,但由于某些原因,查询时索引未能被使用,导致查询性能下降。接下来我会详细讲述常见的七个索引失效场景及其原因。

第一个是,当查询条件中==使用了函数或表达式操作时==,索引会失效。例如,在查询中对索引列使用了 UPPER()、LOWER() 或其他函数操作,数据库无法直接利用索引,因为索引存储的是原始值,而不是经过函数处理后的值。类似的,如果在索引列上进行数学运算(如 age + 1),也会导致索引失效。

第二个是,当查询条件中使用了==类型隐式转换==时,索引会失效。例如,如果索引列是字符串类型,而查询条件中传入的是数字类型,数据库会尝试将字符串列转换为数字进行比较,这种隐式转换会导致索引失效。正确的做法是确保查询条件的数据类型与索引列的数据类型一致。

第三个是,当查询条件中==使用了 LIKE 并以通配符 % 开头时,索引会失效。例如,LIKE ‘%abc’ 这种查询方式会让数据库无法利用索引,因为通配符 % 在开头意味着需要扫描整个表来匹配数据。而如果通配符出现在末尾,如 LIKE ‘abc%’,索引仍然可以生效。LIKE 是一个用于模糊匹配的关键字)==

第四个是,当查询条件中使用了 OR 且部分条件未命中索引时,索引可能失效。例如,如果查询条件是 WHERE indexed_column = ‘value1’ OR non_indexed_column = ‘value2’,即使 indexed_column 上有索引,但由于 non_indexed_column 没有索引,数据库可能会选择全表扫描,从而导致索引失效(扫描全表,所以索引就和没有一样)。(解决方案:为 non_indexed_column 添加索引)

第五个是==,当查询中使用了 NOT 或 != 操作符时,索引可能会失效==。例如,WHERE column != ‘value’ 或 WHERE NOT column = ‘value’ 这样的查询条件通常会导致数据库放弃使用索引,因为这类操作需要扫描大量数据来排除不符合条件的记录。

第六个是,当查询中使用了==复合索引但未遵循最左匹配原则时,索引会失效==。例如,假设有一个复合索引 (A, B, C),如果查询条件只包含 B 或 C,而没有包含 A,那么这个复合索引将无法被使用。只有从最左边的列开始,并按顺序使用索引列,才能有效利用复合索引。

第七个是,当查询中使用了 IS NOT NULL 时,索引可能会失效。虽然 MySQL 支持对 IS NULL 使用索引,但在很多情况下,特别是 IS NOT NULL 的查询,数据库可能会选择全表扫描,从而导致索引失效。

函数运算别乱用,隐式转换要小心;
LIKE 开头 % 失效,OR 混搭全表查;
NOT 等于扫全表,复合索引左匹配;
IS NOT NULL 要注意,索引可能被抛弃。

拓展:

1.什么是最左匹配原则?

最左匹配原则是数据库中使用复合索引(联合索引)时的一个重要规则。它指的是:在查询条件中,必须按照复合索引中字段的顺序,从最左边的字段开始使用,才能充分利用索引。如果跳过了某个字段,则后续字段无法使用索引。

例如,假设有一个复合索引 (A, B, C):

查询条件包含 A 和 B 时,可以利用索引。

查询条件只包含 B 和 C 时,无法利用索引。

查询条件只包含 A 时,可以利用索引。

2.为什么需要满足最左匹配原则?

要理解这一点,我们需要从 B+树的存储结构入手。B+树是一种==多路平衡查找树==,其节点中的键值是按照一定顺序排列的。复合索引的多个字段会组合成一个有序的键值序列,并存储在 B+树的节点中。

(1)复合索引的存储方式

复合索引 (A, B, C) 的存储方式类似于一个多维排序:首先按字段 A 排序;如果 A 相同,则按字段 B 排序;如果 A 和 B 都相同,则按字段 C 排序。

例如,假设我们有以下数据:

ABC
123
125
134
216
227

复合索引 (A, B, C) 在 B+树中的存储顺序为:

(1, 2, 3) -> (1, 2, 5) -> (1, 3, 4) -> (2, 1, 6) -> (2, 2, 7) -> (2, 2, 7)

(2)查询如何利用索引?

B+树的查找过程是从根节点开始,逐步向下查找,直到找到符合条件的叶子节点。为了高效地利用索引,查询条件必须与索引的排序顺序一致。

如果查询条件包含 A=1,可以直接定位到以 A=1 开头的所有记录。

如果查询条件包含 A=1 AND B=2,可以进一步缩小范围,定位到以 (A=1, B=2) 开头的所有记录。

如果查询条件只包含 B=2,由于 B+树的排序首先基于 A,因此无法直接定位到 B=2 的记录,只能进行全表扫描。

2、B+树、B树和红黑树的特点及区别?

B+树、B树和红黑树是常见的平衡树数据结构,尤其在数据库、文件系统和内存中应用的十分广泛。接下来,我将从==十一个方面==详细讲解这三者的特点和区别。

第一个方面是==数据存储位置==。B+树将所有数据存储在叶子节点,非叶子节点只存储索引键;B树则将数据存储在叶子节点和非叶子节点中,所有节点都存储数据;而红黑树则在每个节点中都存储数据。

第二个方面是==叶子节点结构B+树通过链表连接叶子节点,这使得范围查询和顺序遍历非常高效;B树的叶子节点不通过链表连接,用指针,缺乏直接支持范围查询的结构;红黑树没有专门的叶子节点结构,所有节点通过指针==连接。

第三个方面是==索引查找效率==。B+树的查找操作最终都在叶子节点完成,查找路径统一,效率较高;B树的查找操作可能在非叶子节点完成,查找路径不统一,效率稍低;红黑树的查找路径统一,时间复杂度为O(log n),每次操作通过旋转和重新染色来保持平衡。
(B+和红黑树的查找效率都挺高的,但红黑树更适合单个元素的查、插,B+树更适合范围查询)

第四个方面是==树的高度。B+树由于扇出较高(在树形结构中,扇出是指每个节点可以连接的直接子节点的数量。),树的高度通常较低,查询效率较高;B树由于非叶子节点也存储数据,扇出较小,树的高度较高;红黑树作为二叉查找树,树的高度较高,每个节点最多有两个子节点==,树的深度较大(即高度较高,层数多)。

第五个方面是==顺序访问效率。B+树通过链表连接叶子节点,支持高效的顺序访问,尤其在范围查询时表现出色==;B树没有直接的顺序访问机制,顺序访问效率较低;红黑树也缺乏顺序访问机制,顺序遍历效率较低。

第六个方面是==磁盘I/O效率==。B+树由于非叶子节点只存储索引,扇出高,可以减少磁盘访问次数,因此磁盘I/O效率非常优秀;B树稍逊于B+树,因为非叶子节点也存储数据,导致扇出较小,磁盘访问次数略多;红黑树的磁盘I/O效率较差,因为树的高度较高,每次查找可能需要频繁访问磁盘。

第七个方面是==适用场景。B+树常用于数据库索引、文件系统索引,适合大规模数据的存储和检索,尤其在需要高效范围查询时;B树适用于数据库索引和文件系统索引,但相比B+树,查找效率稍低;红黑树适用于内存中的数据结构,如Java中的TreeMap和TreeSet==,适合存储符号表、集合、关联数组等内存数据。

第八个方面是==平衡性==。B+树将所有叶子节点置于同一层,平衡性非常好;B树平衡性较好,但查找路径不统一,效率稍逊;红黑树通过旋转和染色来保持平衡,查找路径统一,操作保持平衡。

第九个方面是==插入/删除操作==。B+树的插入和删除操作可能会引发节点分裂和合并,操作较复杂;B树的插入和删除操作也可能引发节点分裂和合并,操作较复杂;红黑树通过旋转和染色保持平衡,操作相对简单。

第十个方面是==实现复杂度==。B+树的实现较复杂,尤其是在处理链表结构和节点分裂/合并时;B树的实现也较复杂,涉及节点分裂/合并;红黑树的实现相对简单,通过旋转和染色来保持平衡。

第十一个方面是==空间利用率==。B+树的空间利用率较高,非叶子节点只存储索引,存储效率较好;B树的空间利用率较低,非叶子节点存储数据和索引,存储效率较低;红黑树的空间利用率较高,所有节点都存储数据,且由于树的平衡性,内存利用效率较好。

拓展:

1.磁盘的读写过程?

以机械硬盘为例,磁盘中有若干个磁片,磁片中有若干个磁道,查找数据时,需要将磁头移动到磁道上,这个过程属于物理移动,十分耗费时间,通过磁盘高速旋转,这样一次就可以读出来4KB的数据。

![[Pasted image 20251106122314.png]]

2.为什么B+树比B树更矮?

一个数据页(如下图所示)为固定的16KB,里面包含页头,页尾,数据行等等,由于b+树非叶子节点的数据行中只包含了key,每一行占用空间比b树小,大概可以容纳200-300行,这样2000w的数据最多也就3层。

![[Pasted image 20251106122334.png]]

3.B+查询时间更稳定带来的好处?

性能预测更容易:对于数据库管理员和开发者而言,稳定的查询时间让系统性能更可预测,能够更==好地预估响应时间,并且减少出现性能瓶颈的风险。==

一致性体验:对于用户来说,数据库的响应时间更加一致,不会出现时快时慢的情况,尤其在面对大规模数据时,保证用户的体验更加平稳

3、索引的原理

索引(Index)是一种用于加速数据库查询操作的数据结构,它的核心作用是提升查询的速度。从本质上来说,索引的作用就是帮助快速定位有序双向链表中的元素,从而减少数据扫描的范围,提高查询效率。接下来,我会详细讲述索引的基本概念和原理。

第一个是==索引的基本概念==,

索引是数据库中一种独特的数据结构,它并不直接存储表中的数据,而是通过创建一个新的数据结构来指向数据表中的具体记录。可以把它类比为==字典的目录==:当我们查字典时,首先会根据单词的起始字母找到目录页,然后通过目录页中的页码快速定位到具体的单词位置。在这个过程中,目录页就相当于索引表,而目录项就是索引本身。

然而,索引比字典目录更加复杂,因为数据库需要处理动态的数据操作,比如==插入、删除和更新等操作。这些操作会导致索引发生变化==,因此数据库需要维护索引的一致性和高效性。

第二个是==索引的原理==,

当你在MySQL中创建一个索引时, 首先,MySQL会选择一种数据结构来存储索引,最常见的结构是B+树。B+树是一种自平衡的树形结构,叶子节点存储所有数据,而非叶子节点存储索引信息。它的每个节点包含多个键值对,每个键值对指向一个数据块。 然后,索引会根据数据列的值进行排序,将相应的数据行指向叶子节点。

当你执行一个查询时, 首先,MySQL会利用索引的树结构,根据查询条件快速定位到数据的范围,而无需扫描全表。通过从根节点开始,逐层向下遍历B+树,最终可以找到符合条件的数据。 其次,如果索引指向的列已经包含查询条件,MySQL可以直接从索引中获取数据,避免了全表扫描,提高了查询速度。 最后,如果查询条件涉及多个列,MySQL会使用==复合索引==来进一步提高查找效率,通过联合多个列的索引来加速多条件查询。

拓展:

1.索引的分类

按==数据结构==分类,分为B+tree索引、Hash索引和Full-text索引(全文索引);

按==物理存储分类,分为聚簇索引(表只能有一个聚簇索引)和二级索引==(非聚簇索引);

聚簇索引(Clustered Index)是根据数据==表的物理存储顺序==对数据进行索引的一种方式

按==字段特性分类,分为主键索引、唯一索引和前缀索引==;

==主键索引==是基于表中的主键列创建的索引。主键列必须是唯一的,并且不允许有空值(NULL
(每个表只能有一个主键索引,因为表只能有一个主键。主键索引通常是聚簇索引。
在大多数数据库中,如果没有明确指定主键索引,数据库会自动选择一个列作为主键,并创建主键索引。)

==唯一索引==是确保索引列的每个值都是唯一的,即没有重复的值。与主键索引类似,唯一索引也要求列中的每个值都不能重复,但是唯一索引允许有空值(NULL)。

前缀索引是对字符串类型的列进行部分索引。只对列中的前几个字符建立索引,而不是整个字段。这种索引==适用于存储大文本字段==(如长字符串或大数据字段)时,能够减少索引的大小和性能开销。

按==字段个数分类,分为单列索引联合索引==。

2.聚簇索引和非聚簇索引的区别?

聚簇索引和非聚簇索引(也称为二级索引)在==数据存储方式上==存在显著差异。

聚簇索引的叶子节点直接保存了实际的数据记录,这意味着所有用户数据都紧密地与索引结构结合在一起。这种设计使得InnoDB存储引擎在创建表时,会自动为每个表生成一个聚簇索引,以确保数据的高效访问。然而,由于物理存储的限制,一张表只能拥有一个聚簇索引。

相比之下,非聚簇索引的叶子节点并不直接包含数据,而是存储了指向主键值的指针。这意味着当查询使用非聚簇索引时,如果需要获取完整的数据行,系统必须先通过非聚簇索引找到主键值,然后再次访问聚簇索引来获取完整数据,这一过程被称为==“回表”。只有当查询条件完全覆盖了非聚簇索引中的字段时,才能避免回表操作,这被称为“索引覆盖==”。

InnoDB在选择聚簇索引的列时,遵循一定的规则:如果有定义主键,将优先使用主键作为聚簇索引;若无主键,则会选择第一个不包含NULL值的唯一列为聚簇索引;在上述条件均不满足的情况下,InnoDB会自动生成一个隐式自增ID作为聚簇索引的依据。

4、事务的隔离级别

事务的隔离级别是数据库管理系统(DBMS)中用于控制事务并发执行时的数据一致性和并发控制的一种机制。不同的隔离级别决定了事务在执行过程中对其他事务的可见性,从而影响了数据的完整性和查询的准确性。接下来我将详细讲述==四种隔离级别==。

第一种是==读取未提交==(READ UNCOMMITTED),在这个隔离级别下,事务可以读取其他事务尚未提交的数据,可能会发生脏读、不可重复读、幻读。当你在执行一个查询时,如果一个事务正在修改数据,但尚未提交,其他事务仍然可以看到这个未提交的数据。这虽然提供了最高的并发性,但也带来了数据一致性的风险,比如读取到不一致的数据。
(什么是脏读,就是读到中间没提交的数据,改成读取已提交就不会发生脏读了)

第二种是==读取已提交==(READ COMMITTED),在这个隔离级别下,事务只能读取其他事务已提交的数据,可能会发生不可重复读、幻读。当你在执行一个查询时,只有那些已经提交的事务对当前事务可见。然而,不可重复读问题依然存在:如果在同一个事务中多次查询相同的数据,可能会得到不同的结果,因为其他事务可能在查询间修改了数据。
(不可重复读,就是事务执行的时候,数据行可能被别的事务修改了,导致前后读取数据不一致)

第三种是==可重复读(REPEATABLE READ),在这个隔离级别下,事务在执行期间会锁定查询的数据行,确保该数据在事务完成前不会被其他事务修改。当你在执行一个查询时,同一事务中的查询结果不会变化,即使其他事务修改了数据,当前事务也看不到变化的数据==。然而,这个级别仍然存在幻读问题,即在查询过程中,其他事务可能会插入新的数据行,导致当前事务查询的数据集发生变化。
(幻读,当前事务执行的时候,数据会锁定,变化看不到,但实际如果改变了,那就是幻读)

第四种是==可串行化(SERIALIZABLE),在这个隔离级别下,事务的执行会像是串行执行的,即一个事务执行完成后,另一个事务才能开始。当你在执行一个查询时,不仅当前查询的数据不会被修改,其他事务也不能插入新的数据行。这个级别提供了最高的数据一致性==,但代价是性能的显著下降,因为它限制了并发操作。

拓展:

1.MySQL隔离级别 的实现机制

(1)SERIALIZABLE 隔离级别

基于锁实现:在 SERIALIZABLE 隔离级别下,MySQL 使用==表级锁或行级锁==来确保事务的串行化执行。这意味着所有读操作都会被转换为加锁读(即使用 SELECT … FOR UPDATE 或 SELECT … LOCK IN SHARE MODE),从而防止其他事务对同一数据进行修改或读取,确保事务的完全隔离。

Tips:
行级锁就像是你给Excel表格中的某一行或某几行设置了“正在编辑”的锁定状态。只有这几行不能改
表级锁就像是直接把整个Excel表格文件都锁住了。

1. 表级锁的细分
  • 表共享锁:==整个表是只读的。别人可以来读,但不能写。==

  • 表排他锁整个表被独占。别人不能读也不能写

2. 行级锁的细分(以InnoDB为例)
  • 共享锁:对某一行的只读,不能写。

  • 排他锁:对某一行的写入锁,不能读,不能写。

关键点:一个事务对某个表表意向锁*,是为了高效地判断能否对表中的某一行加行锁。*

  • 意向共享锁:事务打算*给表中的某些行设置共享锁。*

  • 意向排他锁:事务打算*给表中的某些行设置排他锁。*
    影响:虽然 SERIALIZABLE 提供了最高的隔离性,但它也带来了最大的性能开销,因为所有的读写操作都需要等待锁的释放。

(2)REPEATABLE-READ 隔离级别(可重复读)

基于 MVCC (Multi-Version Concurrency Control,多版本并发控制) 实现:在 REPEATABLE-READ 隔离级别下,MySQL 主要依赖于 MVCC 来实现一致性读。MVCC 通过维护多个数据版本,使得每个事务都能看到一个一致的数据视图,而不会受到其他事务的影响。
当前读需要加锁:然而,在某些情况下,REPEATABLE-READ 也需要使用锁机制。例如,在进行当前读(如 SELECT … FOR UPDATE 或 UPDATE 操作)时,为了防止幻读现象,MySQL 会使用加锁读来锁定相关行,确保数据的一致性和完整性。

非锁定读与锁定读:在 REPEATABLE-READ 下,普通的 SELECT 查询是不加锁的,称为非锁定读;而涉及更新、删除等操作的查询则需要加锁,称为锁定读。

(3)READ-COMMITTED 和 READ-UNCOMMITTED 隔离级别

基于 MVCC 实现:这两个隔离级别同样主要依赖于 MVCC 来实现。在 READ-COMMITTED 下,每次读取都会看到最新的已提交数据,而在 READ-UNCOMMITTED 下,甚至可以看到未提交的数据(脏读)。

锁的使用:尽管这两个隔离级别主要依赖于 MVCC(读操作靠MVCC),但在涉及到写操作时,仍然需要使用锁机制来保证数据的一致性和完整性。

5、慢查询优化

慢查询优化的关键在于启用慢查询日志并进行深入分析,这能帮助我们识别和优化那些执行效率低下的SQL语句。总体上是通过三个步骤来进行,先捕获低效SQL,然后使用工具进行分析,最后采用一些方法和原则进行优化,接下来我会进行详细讲述。

首先,是捕获低效SQL,在此时我们需要确保==慢查询日志已启用。通过设置全局变量slow_query_log为’ON’来开启此功能,并设定long_query_time参数以确定什么程度的查询延迟被视为“慢”。可以使用SHOW VARIABLES==命令来检查这两个设置的状态,确保配置正确无误。

接下来,我们要==分析慢查询日志,这是找出问题根源的关键步骤。利用工具如mysql dump slow==可以帮助我们总结日志信息,比如按出现频率或总执行时间排序,从而聚焦于最需要关注的查询语句。

对于每一个慢查询,我们可以使用E==XPLAIN命令查看MySQL如何执行这些查询EXPLAIN提供的输出能够揭示查询执行计划中的细节,例如是否进行了全表扫描(ALL),以及哪些索引被使用等==。根据这些信息,我们可以做出更明智的决策来优化查询性能。

最后是,采用一些方法和原则进行优化,常用的方法有4种。

第一种是,建立和优化索引。合理的索引设计可以让查询更加高效,特别是对于经常出现在查询条件、连接条件、排序和分组操作中的字段。同时,删除不再需要的索引也能减少维护开销。

第二种是,对查询本身进行优化,避免不必要的列选择,尽量减少数据传输量,并考虑使用批量或分页查询来处理大数据集。此外,尽量用JOIN替代子查询,因为JOIN通常具有更好的性能表现。(JOIN 是 SQL 中用于将两个或多个表中的数据连接(Combine)起来的操作)

第三种是,调整数据库和系统的配置参数,例如,适当增大InnoDB缓冲池大小、调整临时表的大小限制等,都可以带来显著的性能改进。

第四种是,对于特别大的表,可以考虑采用水平切分或垂直切分策略,通过将数据分散到多个表或数据库实例中,进一步减轻单个实例的压力,改善整体查询性能。

拓展:

1.慢查询的解决方案

解决MySQL慢查询问题的方案可以按照资源消耗从少到多的顺序排列,像金字塔一样逐步提升。以下是从==资源消耗少到多的常见优化方式==:

(1)SQL优化

合理使用索引:确保查询字段使用了索引。对于WHERE、JOIN、ORDER BY、GROUP BY等操作的字段,应该创建相应的索引。

(2)索引优化

创建复合索引:对于多个字段联合查询,创建复合索引(注意索引顺序)。
删除冗余索引:定期清理无用索引,减少索引维护的负担。
避免索引覆盖不必要的字段:有时候一个大字段(如TEXT或BLOB)放入索引会增加存储开销,应该避免。
更新统计信息:定期更新表的统计信息,帮助优化器选择更合适的执行计划。

(3)数据库配置优化

调整缓存设置:增加innodb_buffer_pool_size,确保更多的数据能够缓存到内存中。调整query_cache_size,如果适用,启用查询缓存(对于更新频繁的应用不推荐)。
调整连接设置:如增加max_connections,但要注意数据库承载能力。
max_connections 参数定义了 MySQL 服务器同时能够接受的客户端连接的最大数量。)
调整临时表大小:如果临时表经常写入磁盘,可以通过调整tmp_table_size和max_heap_table_size来避免此问题。
增加排序缓存:增加sort_buffer_size来提高ORDER BY和GROUP BY操作的效率。

(4)架构优化

==分库分表:对于单表数据量过大的情况,使用分库分表策略,将数据分散到不同的数据库或表中,减少每个查询的负载。
读写分离:通过主从复制,减少主库的查询压力,读请求分发到从库。
数据库集群:使用
分布式==数据库系统,解决单机性能瓶颈。

(5)硬件升级

增加内存:通过增加内存,提高缓存命中率,减少磁盘IO。
更换更快的磁盘:使用SSD代替传统的硬盘,提升磁盘IO性能。
增加CPU处理能力:提升CPU性能,减少数据库查询的CPU瓶颈。

Tips:
什么是innodb_buffer_pool_size
想象一个巨大的图书馆(这相当于你的硬盘),里面存放着所有的书(这相当于你的数据)。

每次有读者(相当于一个查询请求)想找一本书,图书管理员都必须跑进书库,找到那本书,然后拿出来给读者。如果图书馆很大,这个过程会非常慢。

为了解决这个问题,图书馆在入口处设置了一个非常大的工作台(这就是 innodb_buffer_pool_size。管理员会把最常被借阅、最热门的书(相当于热数据)提前摆放在这个工作台上。

  • 当读者想要一本热门书时:管理员只需转身从工作台上拿给他,速度极快。这被称为 缓冲池命中

  • 当读者想要一本冷门书时:管理员仍然需要跑进书库去取,速度较慢。这被称为 缓冲池未命中

这个工作台的大小,就是 innodb_buffer_pool_size。工作台越大,能放下的热门书就越多,管理员跑腿的次数就越少,服务读者的平均速度就越快。

http://www.dtcms.com/a/581581.html

相关文章:

  • 网站显示目录北京网站建设华大
  • Go中的泛型编程和reflect(反射)
  • Go Ebiten小游戏开发:扫雷
  • TransformerLLM(大语言模型)的核心底层架构
  • 网站设计的毕业设计百度建设网站
  • 【GitHub热门项目】(2025-11-07)
  • Vue Router (动态路由匹配)
  • python+django/flask的在线学习系统的设计与实现 积分兑换礼物
  • 昇腾Atlas 200I DK A2 C++交叉编译和远程调试教程
  • 2025_11_7_刷题
  • 邓州微网站建设毕业季网站如何做网页
  • 网站是用什么软件做的吗网站设置访问权限
  • AWS + 苹果CMS:影视站建站的高效组合方案
  • 【动手学深度学习】
  • H2 vs SQLite 全面对比
  • python+django/flask的城市供水管网爆管预警系统-数据可视化
  • SQLite 方言解决方案
  • Jenkins + Docker 打造自动化持续部署流水线
  • 利用DeepSeek改写SQLite版本的二进制位数独求解SQL
  • python+django/flask的校园活动中心场地预约系统
  • 建设网站公司哪好html5手机网站开发环境
  • Python高效实现Word转HTML:从基础到进阶的全流程方案
  • 智能驱动,安全可控:EasyGBS平台如何构建企业生产智能监控新模式
  • 建设部网站官网证书查询做网站建设最好学什么
  • 【深度解析】Performance API 与 UKM:从开发者工具到浏览器遥测,全面解锁 Web 性能优化格局
  • 前端项目打包后报错 Uncaught ReferenceError: process is not defined
  • 基于Python的历届奥运会数据可视化分析系统-django+spider
  • 【ZeroRang WebRTC】ICE 在 WebRTC 中的角色与工作原理(深入指南)
  • 计算机视觉(一):相机标定
  • OJ项目面经