【计算基础|MySQL08】索引(上):为什么是 B+ 树

【计算基础|MySQL08】索引(上):为什么是 B+ 树

你上一篇已经知道数据按页存在 .ibd 文件里。那"查一条数据怎么变快"?答案是索引------给数据建个目录。但为什么这个目录偏偏是 B+ 树,而不是你学过的红黑树、哈希表?聚簇索引、二级索引、回表、覆盖索引到底是什么关系?

这篇用 50 万行真实数据说话。先把几种数据结构挨个比一遍,再讲 InnoDB 为什么选 B+ 树,最后实测有索引和没索引的耗时。B+ 树结构、回表过程全用 Mermaid 画。

环境:Docker MySQL 8.0.46,表 blog08.sbtest 共 50 万行(含 id 主键 + k 字段普通索引),实测耗时见正文。


一、索引是什么:数据的目录

结论先给:索引就是一份排好序的数据目录,让你不用翻完整本书就能找到那一页 。没有索引,查 WHERE k=9999 就得把 50 万行从头扫到尾(全表扫描 O(n));有了索引,顺着目录找,O(log n) 就到。

⚠️ 但索引不是越多越好:索引本身也占存储空间,而且每次 INSERT/DELETE 都要同步维护所有索引,拖慢写入。一张表别超过五六个索引。


二、为什么是 B+ 树:六种数据结构逐个淘汰

要给磁盘上的数据建索引,这个数据结构必须满足:树要矮(每层一次磁盘 IO,树越高 IO 次数越多)、支持范围查询、查找快。挨个看:

2.1 哈希表

哈希表 O(1) 查找,确实快。但:

  • 只支持等值查询(=),不支持范围查询 (WHERE k>100 直接抓瞎);
  • 有哈希冲突。

Memory 引擎支持 HASH 索引,但 InnoDB 默认不用它------业务里范围查询太多了。

2.2 二叉搜索树 / 平衡二叉树(AVL)

二叉树每个节点只能有俩孩子,数据一多层就很高。百万行数据,树高约 20 层------每层一次磁盘 IO,查一条要 20 次 IO,慢到没法用。AVL 虽然严格平衡,但旋转开销大、树还是高。红黑树同理,路数少,树照样高。

2.3 B 树(B-Tree)

B 树改成多路 ------一个节点存多个 key、开很多叉,树立刻变矮。但 B 树有个硬伤:非叶子节点也存数据。每个节点(一页 16KB)既要存 key 又要存整行数据,能存的 key 数量就少,扇出小,树又变高了。

2.4 B+ 树(InnoDB 的选择)

B+ 树是 B 树的变种,两个关键改进:

  1. 非叶子节点只存 key,不存数据 → 一页能塞下更多 key,扇出极大,树更矮更胖;
  2. 所有真实数据都存在叶子节点 ,且叶子节点之间用双向链表串起来 → 范围查询顺着链表扫就行。

#mermaid-svg-9uL8OHCMNZwA3oEA{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-9uL8OHCMNZwA3oEA .error-icon{fill:#552222;}#mermaid-svg-9uL8OHCMNZwA3oEA .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-9uL8OHCMNZwA3oEA .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-9uL8OHCMNZwA3oEA .marker{fill:#333333;stroke:#333333;}#mermaid-svg-9uL8OHCMNZwA3oEA .marker.cross{stroke:#333333;}#mermaid-svg-9uL8OHCMNZwA3oEA svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-9uL8OHCMNZwA3oEA p{margin:0;}#mermaid-svg-9uL8OHCMNZwA3oEA .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-9uL8OHCMNZwA3oEA .cluster-label text{fill:#333;}#mermaid-svg-9uL8OHCMNZwA3oEA .cluster-label span{color:#333;}#mermaid-svg-9uL8OHCMNZwA3oEA .cluster-label span p{background-color:transparent;}#mermaid-svg-9uL8OHCMNZwA3oEA .label text,#mermaid-svg-9uL8OHCMNZwA3oEA span{fill:#333;color:#333;}#mermaid-svg-9uL8OHCMNZwA3oEA .node rect,#mermaid-svg-9uL8OHCMNZwA3oEA .node circle,#mermaid-svg-9uL8OHCMNZwA3oEA .node ellipse,#mermaid-svg-9uL8OHCMNZwA3oEA .node polygon,#mermaid-svg-9uL8OHCMNZwA3oEA .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-9uL8OHCMNZwA3oEA .rough-node .label text,#mermaid-svg-9uL8OHCMNZwA3oEA .node .label text,#mermaid-svg-9uL8OHCMNZwA3oEA .image-shape .label,#mermaid-svg-9uL8OHCMNZwA3oEA .icon-shape .label{text-anchor:middle;}#mermaid-svg-9uL8OHCMNZwA3oEA .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-9uL8OHCMNZwA3oEA .rough-node .label,#mermaid-svg-9uL8OHCMNZwA3oEA .node .label,#mermaid-svg-9uL8OHCMNZwA3oEA .image-shape .label,#mermaid-svg-9uL8OHCMNZwA3oEA .icon-shape .label{text-align:center;}#mermaid-svg-9uL8OHCMNZwA3oEA .node.clickable{cursor:pointer;}#mermaid-svg-9uL8OHCMNZwA3oEA .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-9uL8OHCMNZwA3oEA .arrowheadPath{fill:#333333;}#mermaid-svg-9uL8OHCMNZwA3oEA .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-9uL8OHCMNZwA3oEA .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-9uL8OHCMNZwA3oEA .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9uL8OHCMNZwA3oEA .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-9uL8OHCMNZwA3oEA .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9uL8OHCMNZwA3oEA .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-9uL8OHCMNZwA3oEA .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-9uL8OHCMNZwA3oEA .cluster text{fill:#333;}#mermaid-svg-9uL8OHCMNZwA3oEA .cluster span{color:#333;}#mermaid-svg-9uL8OHCMNZwA3oEA div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-9uL8OHCMNZwA3oEA .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-9uL8OHCMNZwA3oEA rect.text{fill:none;stroke-width:0;}#mermaid-svg-9uL8OHCMNZwA3oEA .icon-shape,#mermaid-svg-9uL8OHCMNZwA3oEA .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-9uL8OHCMNZwA3oEA .icon-shape p,#mermaid-svg-9uL8OHCMNZwA3oEA .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-9uL8OHCMNZwA3oEA .icon-shape .label rect,#mermaid-svg-9uL8OHCMNZwA3oEA .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-9uL8OHCMNZwA3oEA .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-9uL8OHCMNZwA3oEA .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-9uL8OHCMNZwA3oEA :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} B+树
双向链表
根节点(非叶子,只存key)

10 | 20 | 30
内部节点

5 | 10
内部节点

15 | 20 | 25
内部节点

30 | 40
叶子(存整行)

1,5,9

叶子

10,15,19

叶子

20,25,29

叶子

30,35,40

🔴 为什么 InnoDB 选 B+ 树,四条理由:

优点 说明
① 树矮 非叶子不存数据,扇出大,3~4 层就能存千万级数据,查一次 3~4 次 IO
② 范围查询快 叶子节点双向链表,WHERE k>10 找到起点后顺着链表扫
③ 查询稳定 任何数据都在叶子节点,每次查找路径长度相同
④ 磁盘预读友好 按 16KB 页读,局部性原理,一次读一整页

面试怎么考:为什么用 B+ 树不用红黑树/B 树/哈希?答:树矮(IO 少)、叶子链表支持范围查询、非叶子不存数据扇出大。


三、聚簇索引 vs 二级索引

3.1 聚簇索引(主键索引)

InnoDB 的主键索引就是聚簇索引 ------它的叶子节点直接存完整的一行数据。一个表只有一个聚簇索引。
渲染错误: Mermaid 渲染失败: Parse error on line 2: ...TD subgraph 聚簇索引(主键) P1["根: ----------------------^ Expecting 'SEMI', 'NEWLINE', 'SPACE', 'EOF', 'GRAPH', 'DIR', 'subgraph', 'SQS', 'end', 'AMP', 'COLON', 'START_LINK', 'STYLE', 'LINKSTYLE', 'CLASSDEF', 'CLASS', 'CLICK', 'DOWN', 'UP', 'NUM', 'NODE_STRING', 'BRKT', 'MINUS', 'MULT', 'UNICODE_TEXT', got 'PS'

如果你没定义主键,InnoDB 会:① 选第一个唯一非空索引;② 再没有就偷偷生成一个 6 字节的 ROW_ID。所以一定要显式定义自增主键。

3.2 二级索引(非聚簇索引)

你建的普通索引(CREATE INDEX idx_k ON sbtest(k))是二级索引。它的叶子节点不存整行,只存主键值。
#mermaid-svg-MkEGk5XiOfeyqPBj{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-MkEGk5XiOfeyqPBj .error-icon{fill:#552222;}#mermaid-svg-MkEGk5XiOfeyqPBj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-MkEGk5XiOfeyqPBj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-MkEGk5XiOfeyqPBj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-MkEGk5XiOfeyqPBj .marker.cross{stroke:#333333;}#mermaid-svg-MkEGk5XiOfeyqPBj svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-MkEGk5XiOfeyqPBj p{margin:0;}#mermaid-svg-MkEGk5XiOfeyqPBj .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-MkEGk5XiOfeyqPBj .cluster-label text{fill:#333;}#mermaid-svg-MkEGk5XiOfeyqPBj .cluster-label span{color:#333;}#mermaid-svg-MkEGk5XiOfeyqPBj .cluster-label span p{background-color:transparent;}#mermaid-svg-MkEGk5XiOfeyqPBj .label text,#mermaid-svg-MkEGk5XiOfeyqPBj span{fill:#333;color:#333;}#mermaid-svg-MkEGk5XiOfeyqPBj .node rect,#mermaid-svg-MkEGk5XiOfeyqPBj .node circle,#mermaid-svg-MkEGk5XiOfeyqPBj .node ellipse,#mermaid-svg-MkEGk5XiOfeyqPBj .node polygon,#mermaid-svg-MkEGk5XiOfeyqPBj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-MkEGk5XiOfeyqPBj .rough-node .label text,#mermaid-svg-MkEGk5XiOfeyqPBj .node .label text,#mermaid-svg-MkEGk5XiOfeyqPBj .image-shape .label,#mermaid-svg-MkEGk5XiOfeyqPBj .icon-shape .label{text-anchor:middle;}#mermaid-svg-MkEGk5XiOfeyqPBj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-MkEGk5XiOfeyqPBj .rough-node .label,#mermaid-svg-MkEGk5XiOfeyqPBj .node .label,#mermaid-svg-MkEGk5XiOfeyqPBj .image-shape .label,#mermaid-svg-MkEGk5XiOfeyqPBj .icon-shape .label{text-align:center;}#mermaid-svg-MkEGk5XiOfeyqPBj .node.clickable{cursor:pointer;}#mermaid-svg-MkEGk5XiOfeyqPBj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-MkEGk5XiOfeyqPBj .arrowheadPath{fill:#333333;}#mermaid-svg-MkEGk5XiOfeyqPBj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-MkEGk5XiOfeyqPBj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-MkEGk5XiOfeyqPBj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MkEGk5XiOfeyqPBj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-MkEGk5XiOfeyqPBj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MkEGk5XiOfeyqPBj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-MkEGk5XiOfeyqPBj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-MkEGk5XiOfeyqPBj .cluster text{fill:#333;}#mermaid-svg-MkEGk5XiOfeyqPBj .cluster span{color:#333;}#mermaid-svg-MkEGk5XiOfeyqPBj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-MkEGk5XiOfeyqPBj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-MkEGk5XiOfeyqPBj rect.text{fill:none;stroke-width:0;}#mermaid-svg-MkEGk5XiOfeyqPBj .icon-shape,#mermaid-svg-MkEGk5XiOfeyqPBj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-MkEGk5XiOfeyqPBj .icon-shape p,#mermaid-svg-MkEGk5XiOfeyqPBj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-MkEGk5XiOfeyqPBj .icon-shape .label rect,#mermaid-svg-MkEGk5XiOfeyqPBj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-MkEGk5XiOfeyqPBj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-MkEGk5XiOfeyqPBj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-MkEGk5XiOfeyqPBj :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 拿到主键id
二级索引 idx_k

叶子存: k值 + 主键id
回表: 再查聚簇索引
聚簇索引叶子: 完整行

查 WHERE k=9999 的过程:

  1. 先在二级索引 idx_k 找到 k=9999,拿到对应的主键 id(50 个 id);
  2. 再拿着这些 id 去聚簇索引 查完整行------这一步叫回表。

3.3 覆盖索引:不用回表

如果查询要的列刚好都在索引里 ,就不用回表了------这叫覆盖索引。比如 SELECT id FROM sbtest WHERE k=9999,idx_k 叶子节点已经有 k 和 id,直接返回,不用再查聚簇索引。EXPLAIN 里 Extra 显示 Using index 就是覆盖索引生效。


四、实测:50 万行数据,索引到底快多少

我们造了一张 50 万行的表 sbtest(id 主键, k, c, pad),先看没索引时 EXPLAIN:

sql 复制代码
EXPLAIN SELECT * FROM sbtest WHERE k=9999;
复制代码
type	possible_keys	key	rows	Extra
ALL	NULL	NULL	497352	Using where

type=ALL、rows=497352------全表扫描 50 万行。建索引:

sql 复制代码
CREATE INDEX idx_k ON sbtest(k);

再看:

复制代码
type	possible_keys	key	rows	Extra
ref	idx_k	idx_k	50	NULL

type=ref、rows=50------只扫 50 行。真实计时(Python 测):

复制代码
主键 id=250000 (聚簇索引):     0.3 ms, rows=1
二级索引 k=9999 (+回表):       0.5 ms, rows=50
覆盖索引 SELECT id (不回表):  0.2 ms, rows=50
全表扫描 k 条件 (约50万行):   32.1 ms, rows=1

🔴 数字说话 :全表扫描 32ms,走索引 0.2~0.5ms------差了 60~160 倍。而且数据量越大差距越夸张,百万、千万行全表扫描能到秒级。

看索引详情:

sql 复制代码
SHOW INDEX FROM sbtest\G
复制代码
Table: sbtest  Key_name: PRIMARY  Seq_in_index: 1  Column_name: id  Cardinality: 493200  Index_type: BTREE
Table: sbtest  Key_name: idx_k     Seq_in_index: 1  Column_name: k   Cardinality: 9984    Index_type: BTREE

重点看 Cardinality(基数):索引列里不重复值的个数。idx_k 基数 9984(k 只有 1 万种值),区分度一般。区分度越低的索引越没用------这是下一篇联合索引和最左前缀要讲的。


五、索引怎么建、有哪几类

sql 复制代码
CREATE INDEX idx_name ON sbtest(k);              -- 普通索引
CREATE UNIQUE INDEX uk_email ON user(email);      -- 唯一索引
ALTER TABLE sbtest ADD INDEX idx_k(k);            -- 另一种建法
DROP INDEX idx_k ON sbtest;                        -- 删索引
SHOW INDEX FROM sbtest;                            -- 看索引详情
索引类型 关键字 特点
主键索引 PRIMARY 聚簇索引,一张表一个,不允许 NULL
唯一索引 UNIQUE 值不重复(但允许多个 NULL)
普通索引 INDEX/KEY 加速查询
联合索引 多个列 按列顺序排序,遵守最左前缀(下篇讲)
全文索引 FULLTEXT 全文检索,MySQL 8 InnoDB 支持

六、面试怎么考

Q1:为什么 InnoDB 用 B+ 树?

非叶子节点不存数据,扇出大、树矮(3~4层存千万级,IO 少);叶子节点双向链表支持范围查询;查询路径稳定;友好磁盘预读。

Q2:聚簇索引和二级索引区别?

聚簇索引叶子存整行数据,一张表一个(主键);二级索引叶子存主键值,查其他列要回表。

Q3:什么叫回表?

二级索引找到主键后,再去聚簇索引查完整行的过程。覆盖索引能避免回表。

Q4:什么是覆盖索引?

查询的列都在索引里,不用回表,EXPLAIN 显示 Using index,是性能优化利器。

Q5:为什么主键推荐自增?

自增主键顺序插入,B+ 树末尾追加,不页分裂;UUID 乱序插入导致频繁页分裂和碎片。

Q6:B+ 树一般多高存千万级数据?

3~4 层(非叶子节点一页能存上千个 key,扇出大)。


总结:你真正需要记住的 7 件事

  1. 索引是数据目录,加速查询但占空间、拖慢写入,别贪多。
  2. InnoDB 选 B+ 树:树矮 IO 少、叶子链表支持范围查询、非叶子不存数据扇出大。
  3. 聚簇索引(主键)叶子存整行,一张表一个;二级索引叶子只存主键。
  4. 二级索引查非索引列要回表;覆盖索引(Using index)免回表,是优化利器。
  5. 实测:50 万行全表扫描 32ms,走索引 0.2~0.5ms,差两个数量级。
  6. 索引区分度(Cardinality)越低越没用,建索引前先看列的重复率。
  7. 主键用自增,顺序写入不页分裂;别用 UUID。

验证清单

  • 能解释为什么不用哈希、红黑树、B 树,而选 B+ 树
  • 默画一棵 B+ 树,标出非叶子只存 key、叶子存数据且双向链表
  • 说清聚簇索引和二级索引叶子节点各存什么
  • 用自己的话讲一遍"回表"过程,并说出怎么避免(覆盖索引)
  • 在本机 sbtest 上复现:全表扫描 ~30ms,走 idx_k ~0.5ms
  • 跑 EXPLAIN,认出 type=ALL(全表扫描)和 type=ref(走索引)
  • 跑 SHOW INDEX,看懂 Cardinality 的含义
  • 说出自增主键为什么能避免页分裂

参考资源


下一篇《索引(下):联合索引、最左前缀与索引失效》:上一篇知道了 B+ 树怎么加速,这篇解决实战中最头疼的问题------为什么我明明建了索引却没生效?联合索引 (a,b,c) 为什么 WHERE c=? 用不上?什么是最左前缀、索引下推、索引失效的常见场景?我们把这些"建了索引却不走"的坑一个个踩给你看。

相关推荐
夊1 小时前
数据结构第二课:顺序表揭秘
数据结构
吠品1 小时前
Flutter 工程配本地 Maven 引 AAR,仓库声明为啥不生效
c语言·人工智能·算法
microrain1 小时前
专业版守核心,企业版做增量:SagooIoT 的跨模块能力出口
物联网·架构·golang·sagooiot
罗湖老棍子1 小时前
【例题1】黑暗城堡(信息学奥赛一本通- P1486)
算法·图论·最短路·dijkstra·最小生成树·最短路径生成树
学linux的QQ蛋1 小时前
IMX6 嵌入式多传感器系统整体架构梳理
linux·嵌入式硬件·架构
布莱克6051 小时前
QtWidgets 与 QML:两大 UI 开发框架的全面对比
开发语言·c++·qt·ui·架构
hetao17338371 小时前
2026-10-20 hetao1733837 的刷题记录
c++·算法
我不会插花弄玉2 小时前
9. 表的内连和外连【由浅入深-MySQL】
android·数据库·mysql