news 2026/10/28 1:46:26

字节一面,被连问 MySQL 索引,脸都问绿了

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
字节一面,被连问 MySQL 索引,脸都问绿了

一、开篇:那些被 MySQL 索引支配的恐惧

字节一面的面试官,通常会从你的简历里挑一个最熟悉的技能点开始切入。如果你写了「熟悉 MySQL」「掌握索引优化」,那么接下来半小时,索引问题会像连环炮一样砸过来:

  • 为什么用 B+ 树,不用 B 树、哈希表、红黑树?
  • 聚簇索引和非聚簇索引有什么区别?什么叫做回表?
  • 联合索引为什么会有最左前缀原则?
  • 什么情况下索引会失效?LIKE 模糊查询一定失效吗?
  • 什么是索引下推?什么是覆盖索引?
  • 三千万数据怎么建索引?为什么推荐自增主键?
  • EXPLAIN 里的 type、rows、Extra 分别代表什么?

很多候选人能背出「索引是帮助 MySQL 高效获取数据的数据结构」,也能说出「B+ 树矮胖、查询稳定」,但一旦被追问底层细节、执行计划和实际设计,就会露怯,脸越问越绿。

这篇文章从面试实战出发,把 MySQL 索引相关的核心知识一次讲透。它不是零散知识点的堆砌,而是一条完整主线:索引是什么 → 凭什么快 → 底层结构长什么样 → 有哪些种类 → 联合索引怎么用 → 为什么会失效 → 执行计划怎么看 → 生产环境怎么设计索引。全文约两万字,建议收藏后分几次读完,面试前再重点过一遍。

阅读提示:本文默认读者了解基础的 SQL 语法和数据库概念,但不要求深入理解存储引擎。文中所有实验均基于 MySQL 8.0 与 InnoDB 存储引擎。


二、索引是什么:先纠正一个长期误区

2.1 索引不是「目录」那么简单

很多人把索引类比成书的目录,这个类比能帮助理解,但不够准确。更贴切的类比是:索引是一张独立维护的、指向实际数据位置的有序数据结构。它保存的是「索引键值」到「数据行位置」的映射,并且这些键值按一定规则排序。

当你在 1000 万行的用户表里执行下面这条 SQL:

SELECT * FROM user WHERE phone = '13800138000';

如果没有索引,InnoDB 会从表的第一行开始,一行一行地比对 phone 字段,直到找到目标行或者扫完整个表。这叫全表扫描,时间复杂度是 O(N)。1000 万行数据,哪怕每行很快,整体也是秒级以上,而且会占用大量磁盘 IO 和 CPU。

有了 phone 字段的普通索引后,MySQL 先在索引结构里按 phone 值快速定位,得到目标行的主键值,再回主键索引里拿数据。整个过程是 O(log N) 级别,几乎可以做到毫秒级返回。

2.2 索引的本质:用空间换时间

索引一定是有代价的,这个代价体现在三方面:

  • 存储空间:索引本身占磁盘。每多建一个索引,就多一份结构化的冗余数据。
  • 写性能:插入、更新、删除数据时,除了维护表数据,还要同步维护所有相关索引。索引越多,写操作越慢。
  • 维护成本:数据量大以后,索引页分裂、合并、重建都会产生额外开销。

所以「索引越多越好」是完全错误的。生产环境里,一个表的索引数量通常要克制,单表索引建议控制在 5 个以内,并且每一个都要有明确的使用场景。

2.3 面试题:索引能提高查询效率,那它能提高写入效率吗?

答案是不能,通常还会降低写入效率。因为写入一条数据时,表数据要写,所有相关索引也要写。索引越多,随机 IO 越多,写放大越严重。面试官如果追问「为什么主键索引的写入可能比普通索引更快」,可以从两点回答:一是主键索引是聚簇索引,数据本身就是按主键组织的,一般按主键有序追加即可;二是普通索引的维护涉及在非主键树上找插入位置,分散度更高。更深层的答案还可以延伸到「自增主键避免页分裂」。


三、索引凭什么快:先讲清楚磁盘 IO 这件事

3.1 慢的不是 CPU,是磁盘

理解索引之前,必须先理解一个硬件事实:机械磁盘的一次随机读写寻道时间是毫秒级(约 5 到 10 毫秒),而内存的一次随机访问是纳秒级。两者相差百万倍。即使现在普遍使用 SSD,随机 IO 依然比顺序 IO 慢一个数量级以上。

MySQL 的数据和索引默认都持久化在磁盘上。查询时,目标数据所在的「页」会被加载到内存的 Buffer Pool 里。所谓「查询慢」,绝大多数时候不是慢在 CPU 比对,而是慢在需要做多少次磁盘 IO。

所以索引设计的第一目标,是减少磁盘 IO 次数。一棵矮胖的树,能在几次 IO 内定位到目标数据,这就是 B+ 树的价值所在。

3.2 页:InnoDB 的最小读写单位

InnoDB 存储引擎里,磁盘和内存交互的最小单位是页(Page),默认大小 16KB。一个页里可以放多条记录,也可以放多个索引节点。一次磁盘 IO 读进来的不是一个索引节点,而是一整个页。

这个「页」的概念非常重要,后续讲 B+ 树、页分裂、覆盖索引、最左前缀时都会反复用到。面试官问「为什么说某个索引查询快」,本质上是问「这个查询要读多少个页」。

页的内部结构简要如下:

  • File Header / File Trailer:页的元信息、校验信息。
  • Page Header:页内记录条数、空闲空间、槽位信息等。
  • Infimum + Supremum:两个虚拟记录,分别代表最小值和最大值边界。
  • User Records:真正的数据记录,按主键顺序以单向链表组织。
  • Page Directory:页目录,通过「槽」对页内记录做分组,用于页内快速查找。

面试被问到「一条记录在一个页里是怎么找到的」,可以这样答:先在页目录里用二分法定位到某个槽,再在该槽对应的记录组内顺序遍历,找到目标记录。这样页内查找也不需要逐条扫描。

3.3 为什么「有序」是索引的命根子

索引结构要能快速定位,前提是键值有序。有序之后才能二分查找、范围查找、排序。如果数据无序,就只能挨个比对。

面试官常问:「为什么加了索引,ORDER BY 会变快?」答案就是:索引本身已经按某个键排好序了,沿着索引扫描天然就是有序结果,省去了额外排序(filesort)。这一点后面讲 filesort 时还会详细展开。


四、索引的数据结构:从哈希到 B+ 树的演进

4.1 哈希表:等值查询快,范围查询直接报废

哈希索引基于哈希表实现。对于等值查询,比如:

SELECT * FROM user WHERE phone = '13800138000';

哈希索引先用哈希函数对 phone 计算哈希值,直接定位到对应的桶,理想情况下 O(1) 就能找到。

但哈希索引的问题非常明显:

  • 不支持范围查询:phone 大于某个值、小于某个值,哈希表无能为力。
  • 不支持排序:哈希后的值没有顺序,ORDER BY 用不上它。
  • 不支持部分键匹配:联合索引 (a, b),哈希索引只对完整键生效。
  • 哈希冲突:冲突严重时性能退化,需要链表或再哈希解决。

MySQL 中,Memory 存储引擎默认使用哈希索引;InnoDB 也支持自适应哈希索引(Adaptive Hash Index),不过那是引擎自动创建和维护的,用于加速热点页的等值查询,不是用户手动创建的索引类型。

面试话术总结:哈希索引适合纯等值、低重复度、无需排序的场景,通用性差,MySQL 主选 B+ 树。

4.2 二叉搜索树与红黑树:内存里好用,磁盘上高度失控

二叉搜索树在理想情况下查找是 O(log N),但如果插入顺序恰好有序,比如主键 1、2、3、4、5 依次插入,树会退化成链表,查找变成 O(N)。

红黑树作为自平衡二叉搜索树,保证了最坏情况 O(log N),高度约为 2logN。看上去不错,但它仍然是二叉树:每个节点只存一个键值,分叉只有两个。当数据量达到千万级别时,树的高度会非常大。

假设红黑树维护 1000 万条索引记录,高度大约在 2 × log₂(10⁷) ≈ 47 层。最坏一次查找要访问约 47 个节点。如果这些节点分散在不同磁盘页上,那一次查询就可能触发四十多次随机 IO,性能不可接受。

结论一句话:红黑树不是不好,而是它「太高了」,不适合磁盘场景。磁盘场景需要的是「矮胖多叉树」。

4.3 B 树:多叉了,但还不够「纯粹」

B 树是平衡多路搜索树,每个节点可以存多个键值,并且有多个子节点。一个 m 阶 B 树满足:每个节点最多 m 个子节点,每个非叶子节点存储键值和指针。B 树把树的高度大幅降低,减少了 IO 次数。

但 B 树有一个关键特征:数据(或数据指针)可以存储在非叶子节点上。也就是说,查找命中时,可能在非叶子节点就拿到数据了。

这对 IO 有什么影响?因为每个节点所在的页大小固定(16KB),非叶子节点既要存索引键,又要存数据记录,单页能容纳的「键」数量就会变少,树的高度相应变高。对磁盘数据库来说,我们希望非叶子节点尽可能只存索引信息,塞进更多的键,把树做得更矮。

4.4 B+ 树:为磁盘而生的终极答案

B+ 树是 B 树的变体,也是 MySQL InnoDB 索引的底层结构。它的核心特点:

  • 非叶子节点只存键和子节点指针,不存数据。所有数据(或数据地址)都放在叶子节点。
  • 叶子节点形成有序双向链表,按索引键顺序串联,支持高效范围扫描。
  • 叶子节点包含全部键值,非叶子节点的键只是用于导航的「路标」。
  • 查询任何数据都必须走到叶子节点,所以所有查找的 IO 次数基本一致,性能稳定。

来算一笔账。InnoDB 的页大小默认 16KB。假设索引键是 bigint(8 字节),指向子节点的指针在 InnoDB 里约 6 字节,那么一个非叶子节点页大约能存:

16384 / (8 + 6) ≈ 1170 个键

也就是说,一个非叶子节点页可以拥有约 1170 个子节点。如果一棵 B+ 树高度为 3,那么它能容纳的叶子节点大约为:

1170 × 1170 = 1368900 个叶子页

假设每个叶子页能存约 16 条完整记录(按一行 1KB 估算),那么 3 层 B+ 树大约能容纳 2000 多万条记录。对一个千万、上亿级别的表,树的高度通常只有 3 到 4 层。

这意味着:一次基于主键的查询,最多只需要 3 到 4 次磁盘 IO,其中根节点大概率常驻内存,实际 IO 往往只有 2 到 3 次。这就是 B+ 树为什么适合磁盘数据库的根本原因。

4.5 B+ 树 vs B 树的面试对比清单

对比维度B 树B+ 树
数据存放非叶子节点也可存数据只有叶子节点存数据
单页可容纳键数较少,树相对更高更多,树相对更矮
查询 IO不稳定,最好 O(1) 次命中根节点稳定,每次都要走到叶子
范围查询需要中序遍历,路径分散叶子链表顺序扫描,效率高
全量扫描需要遍历整棵树沿叶子链表顺序遍历即可

面试回答模板:「B+ 树非叶子节点不存数据,同样大小的页能容纳更多键,因此树更矮,磁盘 IO 更少;同时叶子节点用双向链表串联,范围查询和全表遍历都可以顺序完成,非常适合磁盘场景。而 B 树虽然查找最好情况更快,但查询性能不稳定,范围扫描也低效。」

4.6 附加题:为什么不用跳表?

有些候选人会主动提到跳表。跳表在 Redis 的 ZSet 里用得很多,内存场景查询和插入都是 O(log N),实现也简单。那 MySQL 为什么不用跳表?

关键还在磁盘 IO。跳表在内存里靠指针随机跳转,它的节点分布是随机的,相邻逻辑节点在磁盘上不一定相邻。对磁盘来说,跳跃访问大量随机页非常低效。而 B+ 树把多个键紧凑放在同一个页里,一次 IO 能读进大量键,天然适合磁盘的批量预读特性。

可以这么总结:跳表赢在内存和实现简单,B+ 树赢在磁盘友好和范围扫描。


五、聚簇索引与非聚簇索引:先分清这两棵「树」

5.1 聚簇索引:数据和索引长在一起

InnoDB 中,表数据文件本身就是按主键组织的一棵 B+ 树。这棵树的叶子节点里存的是完整的行数据。这棵按主键构建的 B+ 树,就是聚簇索引(Clustered Index)。

正因为数据就是索引的一部分,所以 InnoDB 表必须有且只能有一个聚簇索引。数据不可能同时按两个顺序物理存储两份。

主键选择的优先级:

  • 显式定义的主键优先;
  • 没有主键时,选择第一个「非空唯一索引」作为聚簇索引;
  • 既没有主键也没有符合条件的唯一索引时,InnoDB 会生成一个隐藏的 6 字节 row_id 作为聚簇索引。

面试时被问「没有主键会怎样」,除了会说依然能建表外,还要主动补充:隐藏 row_id 对用户不可见,且全局共享一个计数器,并发插入高时有竞争,还可能造成主从不一致等问题,不推荐。

5.2 非聚簇索引(二级索引):叶子存的是主键值

你手动创建的普通索引、唯一索引、联合索引,在 InnoDB 里都是二级索引(Secondary Index),也叫辅助索引。它们的 B+ 树叶子节点里不存完整行数据,而是存索引键 + 对应主键值。

也就是说,一张表里有多少个普通索引,就有多少棵独立的 B+ 树。每棵二级索引树都比聚簇索引「轻」,因为没有携带完整行数据。

5.3 回表:一次查询为什么要跑两棵树

现在看这条查询:

SELECT * FROM user WHERE phone = '13800138000';

假设 user 表的完整结构如下:

CREATE TABLE user ( id BIGINT PRIMARY KEY, phone VARCHAR(20), name VARCHAR(64), KEY idx_phone(phone) ) ENGINE=InnoDB;

执行SELECT *时,MySQL 要做两件事:

  • 第一步,在 phone 的二级索引树上定位'13800138000',拿到叶子节点里保存的主键值,假设是id = 9527;
  • 第二步,拿着id = 9527回到聚簇索引树继续查找,才能拿到这一行的 name 等完整字段。

这个「先查二级索引,再回到聚簇索引取完整行数据」的过程,就叫回表。

回表的本质是:二级索引里只存了「phone + 主键 id」,并没有 name。想拿到 name,就必须再跑一棵树。所以SELECT *在命中二级索引后,往往是两次索引查找;如果你只查SELECT id FROM user WHERE phone = ...,在二级索引叶子节点上就能直接拿到结果,一次回表都不用做。

面试时要会延伸:为什么建议尽量少写SELECT *?因为会带来不必要的回表。优化手段就是接下来要讲的覆盖索引和索引下推。

六、联合索引与最左前缀原则

6.1 联合索引:先会建,再懂它怎么存

联合索引也叫复合索引,就是在一张表上同时给多个列建一个索引,例如:

ALTER TABLE user ADD INDEX idx_name_age(name, age);

它看起来只有一行 DDL,实际上底层只对应一棵 B+ 树,并不是给 name 建一棵、给 age 再建一棵。这棵树的排序规则是:先按 name 排序,name 相同再按 age 排序。

这就好比字典先按拼音首字母排,首字母相同再按第二字母排。理解这一点,是理解最左前缀的关键。

6.2 最左前缀原则:从最左列开始逐层匹配

联合索引(name, age)的查找,必须从最左边的 name 开始,像走楼梯一样逐层往下走。如果跳过了最左列,MySQL 就不知道该从哪一段开始二分了。

举例:

-- 命中索引:从 name 开始 SELECT * FROM user WHERE name = '王小明'; -- 也命中:先 name 再 age SELECT * FROM user WHERE name = '王小明' AND age = 25; -- 部分命中:name 等值,age 走范围 SELECT * FROM user WHERE name = '王小明' AND age > 20; -- 不命中:直接跳过 name,用 age SELECT * FROM user WHERE age = 25;

为什么WHERE age = 25用不上(name, age)?因为在这棵 B+ 树里,所有数据先按 name 排序,age 只在「同一个 name 内部」才有序。单独拿 age 过滤,索引帮不上忙,只能全表扫描。

6.3 范围查询断档:范围列之后的列不再生效

再看一道高频变形题:

SELECT * FROM user WHERE name = '王小明' AND age > 20 AND city = '北京';

如果索引是(name, age, city),那么 name 可以精确匹配,age 走范围扫描,但city 这一列基本用不上。因为 age 一旦进入范围查询,后面的 city 已经不再保持有序,这叫做「范围查询断档」。

这也是为什么建立联合索引时,通常把等值判断的列放前面,范围查询的列放最后。

6.4 面试题:联合索引 (a,b,c),哪些查询能命中?

提供一个面试回答框架:

  • 建该索引相当于获得了 (a)、(a,b)、(a,b,c) 三种查询效果,但并不等于单独建了 (b) 或 (b,c);
  • 只要条件从 a 开始,并且没有跳过中间列,通常能部分或全部命中;
  • 如果 a 使用了范围条件,后面的 b、c 基本失效;如果 a、b 都是等值,c 可以继续被利用。

面试时能说清「从最左列开始、遇到范围查询断档」这两层逻辑,就能把最左前缀讲透。

七、覆盖索引与索引下推:减少回表的两把利器

7.1 覆盖索引:查到的东西全在叶子里

如果一条查询需要的字段,全部都能在二级索引的叶子节点里找到,就不用回表。这种场景叫覆盖索引。

SELECT id, name FROM user WHERE name = '王小明';

假设有索引(name),它的叶子节点里除了 name,还会携带主键 id。这条 SQL 要的正好就是 id 和 name,因此从头到尾只访问二级索引这一棵树,EXPLAIN 的 Extra 会显示Using index。

覆盖索引的价值就是:减少回表次数,也就是减少磁盘 IO。这正是对 5.3 节回表知识点的呼应。

7.2 索引下推:能在引擎层过滤,就不要先回表

索引下推(Index Condition Pushdown,ICP)是 MySQL 5.6 开始引入的优化。它解决的问题是:联合索引中部分列用上以后,剩余条件本来要回表再过滤,现在可以先在存储引擎层把能判断的条件判断掉。

SELECT * FROM user WHERE name LIKE '王%' AND age = 25;

假设索引是(name, age),name 走前导模糊还能利用前缀缩小范围,age 因为排在 name 之后原本很难享受索引。但开启 ICP 后,引擎在扫描 name 匹配出来的索引记录时,会顺手在索引里过滤 age,减少不必要的回表。

面试时记住一句话:覆盖索引用来「不回表」,索引下推用来「晚一点回表、少回一点表」。

八、索引失效的常见场景

这一节是面试重灾区。重点不是背「八条规律」,而是理解背后的共同原因:索引列的值被破坏、类型不一致、条件无法定位有序区间,或者优化器认为走索引更贵。

8.1 对索引列做函数或运算

-- 失效:对索引列套函数 SELECT * FROM user WHERE DATE(create_time) = '2024-01-01'; -- 可用:让字段保持裸着 SELECT * FROM user WHERE create_time >= '2024-01-01 00:00:00' AND create_time < '2024-01-02 00:00:00';

因为索引里存的是 create_time 的原始值,套上 DATE() 后,MySQL 无法直接利用有序结构定位。

8.2 隐式类型转换

-- phone 是 VARCHAR,却传入整数 SELECT * FROM user WHERE phone = 13800138000;

MySQL 会悄悄把 phone 列转成数字再比较,等于对索引列做了函数操作,索引失效。正确做法是写成字符串:

SELECT * FROM user WHERE phone = '13800138000';

8.3 前导模糊查询

-- 通常失效:% 在开头 SELECT * FROM user WHERE name LIKE '%小明'; -- 可用:% 在末尾 SELECT * FROM user WHERE name LIKE '王%';

因为 B+ 树按 name 排序,「王%」还能利用前缀缩小范围,而「%小明」不知道从哪里开始,只能全表扫描。

8.4 OR 混用

OR 两边如果有非索引列,优化器可能放弃索引:

SELECT * FROM user WHERE name = '王小明' OR remark = 'VIP';

即便 name 有索引,remark 没索引,也可能退化为全表扫描。可以考虑拆成两条 SQL 用 UNION,或者给 remark 也建立索引。

8.5 违反最左前缀原则

这是第六节的延续:跳过联合索引的最左列,后面的列都用不上,这里不再重复。

8.6 索引失效要结合 EXPLAIN 判断

「失效」不是背出来的,而是用 EXPLAIN 看出来的。下一步就讲执行计划。

九、执行计划 EXPLAIN 怎么看

9.1 先看 type:判断访问方式的重中之重

EXPLAIN 输出里,type 从好到差大致是:

system > const > eq_ref > ref > range > index > ALL

重点记这几个:

  • const:用主键或唯一索引做等值查询,最多命中一行;
  • ref:用普通索引做等值匹配;
  • range:索引范围查询,比如 >、<、BETWEEN、LIKE '王%';
  • ALL:全表扫描,也就是常说的「索引失效了」。

面试官问「这条 SQL 走没走索引」,本质上是问 type 是不是 ALL。

9.2 再看 rows、key、Extra

  • key:实际命中的索引名,NULL 通常代表没走索引;
  • rows:优化器估算要扫描的行数,数值越大越危险;
  • Extra:像 Using index(覆盖索引)、Using where(服务层过滤)、Using filesort(额外排序)、Using temporary(临时表)都写在这里。

特别提醒:Using filesort表示 MySQL 额外做了一次排序。如果 ORDER BY 的列能顺着索引有序扫描,就不会出现它。这也是 3.3 节「索引能让 ORDER BY 变快」的落地解释。

十、生产环境索引设计实战

10.1 为什么推荐自增主键

自增主键让新数据排在聚簇索引的最后,写入时是顺序追加,不容易触发页分裂。而 UUID 这类随机值会让插入位置随机分布,频繁页分裂,写性能和空间利用率都差。

所以高并发写入场景,优先用自增 BIGINT 主键。

10.2 唯一索引还是普通索引

如果业务上能保证唯一性,就用唯一索引,它兼具数据约束和查询加速。如果只是想加速查询,普通索引通常足够。唯一索引和普通索引在「按等值查询一条记录」上的性能差异很小,别为了加速而硬加唯一约束。

10.3 三千万数据怎么建索引

  • 先看查询画像:梳理所有高频 SQL,把 WHERE、ORDER BY、GROUP BY 关联的列都列出来;
  • 合并冗余:能用联合索引解决的,就不要建多个单列索引;
  • 区分度优先:性别这种低区分度列单独建索引意义不大;
  • 控制数量:单表索引建议控制在 5 个以内,写多读少的表要更克制。

10.4 索引不是越多越好

每多一个索引,INSERT、UPDATE、DELETE 就要多维护一棵 B+ 树。设计索引的本质是:在查询加速和写操作成本之间做平衡。

十一、总结:把整条主线串起来

回到开篇那条主线,现在可以完整串起来:

  • 索引是什么:用空间换时间的有序结构;
  • 凭什么快:减少磁盘 IO,核心是页和有序;
  • 底层结构:经过哈希、二叉搜索树、红黑树、B 树的演进,最终选择 B+ 树;
  • 有哪些种类:聚簇索引与二级索引,回表是二者协作的核心;
  • 联合索引怎么用:最左前缀原则,避免范围断档;
  • 为什么会失效:函数运算、类型转换、前导模糊、OR、违反最左前缀;
  • 执行计划怎么看:先看 type,再看 key、rows、Extra;
  • 生产怎么设计:自增主键、索引克制、按查询画像建联合索引。

面试时,把上面这条主线完整讲下来,比零散背 20 个知识点更能体现体系化理解。建议把文中 SQL 全部在本地 MySQL 8.0 上跑一遍,再用 EXPLAIN 验证一次,印象会深得多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 1:46:08

AI游戏画面分析与趣味吐槽技术解析

1. 项目背景与核心价值最近在游戏社区看到一个很有意思的现象&#xff1a;越来越多的玩家开始用AI工具对游戏画面进行技术分析和趣味吐槽。这种结合了技术解析和娱乐点评的内容形式&#xff0c;正在成为游戏圈的新潮流。作为一个常年混迹游戏圈的老玩家&#xff0c;我发现这种内…

作者头像 李华
网站建设 2026/10/28 1:45:37

嵌入式开发笔记随记

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:42:38

Python计算机视觉实战:手势识别、虚拟键盘与姿态检测

简介&#xff1a;这份合辑面向已具备Python基础、希望上手计算机视觉与人工智能应用的学习者&#xff0c;围绕手势识别、虚拟键盘、姿态检测等典型场景组织调试通过的示例&#xff0c;可用于课程实验、毕业设计选题参考与个人项目练手。压缩包共35个文件&#xff0c;约16.91MB&…

作者头像 李华
网站建设 2026/10/28 1:42:17

卫星遥感遥感算力集群:从单机瓶颈到规模化生产的落地路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/28 1:42:17

改性HDPE再生颗粒重塑户外家具发泡板材价值:以技术赋能破解工艺痛点、升级客户原料使用习惯

1. 核心观点改性HDPE再生颗粒通过分子结构调控与熔体强度优化&#xff0c;可从材料端解决户外家具挤出HDPE发泡板材的发泡倍率低、泡孔不均匀、表面凹凸不平、产品不够轻便与成本居高不下的核心痛点。 轻质家具板材市场2024年规模34.5亿美元、预计2032年达61.8亿美元&#xff0…

作者头像 李华