第三章 索引基本概念:B树、哈希索引、位图索引

聊到索引,很多刚入行的同学第一反应就是“查得快”。但到底怎么个快法?每种索引的脾气秉性又是什么?今天我得给你掰扯清楚。

我个人习惯把索引比作书的目录。但实际工程里,索引的玩法可比目录复杂多了。B树、哈希、位图,这三兄弟各有绝活,也各有软肋。

三种索引类型对比:B树、哈希索引、位图索引 索引类型核心逻辑概览 索引类型 B树 (B-Tree) 平衡多路查找树 有序存储 · 支持范围查询 哈希索引 (Hash) 键-值哈希映射 等值查询最快 · 不支持范围查询 位图索引 (Bitmap) 位数组存储 低基数列 · 位运算极快 典型应用场景 B树 → 范围查询/排序 哈希 → 精确匹配/主键查找 位图 → 数据仓库/统计 (如:日志时间范围查询) (如:根据订单ID查记录) (如:用户状态标签统计)

3.1 B树索引:最通用的老朋友

B树,不是二叉树,是平衡多路查找树。我刚开始接触B树时也犯过糊涂,以为它就是个带平衡的二叉树变种。其实完全不是一回事。

B树的核心思想:每个节点可以存多个键值,有多个分支。这样就大大降低了树的高度。你想想看,一个3层的B树就能轻松管理几千万条数据。

B树的几个关键特性:

  • 有序性:数据按索引列排序存储。所以B树天然支持 ORDER BY 和范围查询。
  • 自平衡:插入删除时会自动调整结构,保证查询稳定。
  • 多路分支:每个节点可以分很多岔,树矮,IO次数少。

我在项目中遇到过一个问题:审计日志表数据量大概5亿行,按时间戳查询某个范围,没加索引时跑了8分钟。我建了一个B树索引,查询直接降到了200毫秒。效果立竿见影。

核心优势: 最平衡,适用范围最广。大部分关系型数据库的默认索引就是B树(或其变种B+树)。

小提示: 建B树索引注意 列的区分度。我用性别列(男女)建B树索引,几乎没有效果。因为区分度低,查出来的数据量太大了。

3.2 哈希索引:等值查询的闪电侠

哈希索引,说白了就是把键值通过哈希函数算出一个位置,然后直接去这个位置找数据。你给它一个值,它立马算出位置,一步到位。

哈希索引的优点:

  • 等值查询极快,常数级别。比B树还快。
  • 非常适合主键或唯一键的精确匹配。

但它的致命弱点也很明显:

  • 不支持范围查询:比如 WHERE create_time > '2024-01-01',哈希索引没法用。
  • 不支持排序:因为数据是乱序存的。
  • 哈希冲突:多个值映射到同一位置,需要链表处理,影响性能。

我记得在优化一个日志详情查询接口时,接口接收一个 trace_id 做精确搜索。当时用了几百万条数据压测,B树索引走了几百毫秒,换成哈希索引后,直接降到了 10 毫秒以内。这就是哈希索引的威力。

避坑指南: 我曾经在MySQL的InnoDB存储引擎下,看文档说用 UNIQUE 和 = 查询会自动用哈希索引。其实InnoDB不支持真正的哈希索引,它用的是自适应哈希索引(内部自动管理的 AHI),你没法手动创建。所以请确认你使用的数据库是否真的支持哈希索引(比如 MEMORY 引擎、Redis)。

对比维度 哈希索引 B树索引
等值查询 极快 (O(1)) 较快 (O(log n))
范围查询 不支持 支持 (天然有序)
排序 不支持 支持
哈希冲突 有影响 无此问题
适用场景 主键/唯一键等值搜索 范围查询、排序、通配

3.3 位图索引:大数据分析的利器

位图索引,你可能在OLAP系统中见得比较多。它用位数组表示数据,每个位代表一行,1表示该行有该值。我最早接触它是在Oracle的数据仓库实践中。

核心思想: 把每个不同的值建一个位图。比如性别列(男、女),男对应一个位图(100101...),女对应另一个位图(011010...)。

-- 假设10行数据,性别为男的位图
行号:  1  2  3  4  5  6  7  8  9  10
男:    1  0  1  0  0  1  1  0  0  0
女:    0  1  0  1  1  0  0  1  1  0

优点:

  • 存储空间极小,尤其是低基数(唯一值少的列)。
  • 位运算(AND/OR)极快,适合多条件组合查询。

缺点:

  • 不适合高基数列(比如用户ID、手机号)。一个值建一个位图,基数高时位图数量巨大。
  • 不适合频繁更新。每一次更新都可能需要长事务或重建位图。

最佳实践: 位图索引在审计日志分析的 标签统计 场景下特别好用。比如分析“操作类型=删除 AND 状态=失败”的日志数量,位运算只需几毫秒。

3.4 如何选择?

你可能会问,我到底该用哪个?我整理了一个简单的选择指南:

  1. 第一步:确认你的查询类型。
    • 等值查询多 → 优先考虑哈希索引(如果数据库支持)。
    • 范围查询、排序多 → 必须用B树索引。
    • 组合条件统计、分析和低基数列 → 位图索引。
  2. 第二步:确认列的数据分布。
    • 高区分度(如日志ID、时间戳)→ B树、哈希。
    • 低区分度(如状态码、操作类型)→ 位图。
  3. 第三步:确认写入压力。
    • 写入频繁 → 慎用位图索引。
    • 读多写少 → 位图非常香。

我的经验: 在审计日志系统中,时间列一般用B树索引(因为要查范围)。操作类型列(比如insert/delete/update),如果操作类型数量很少(不超过20种),我建议建位图索引。我曾经用位图索引替换掉B树索引后,查询性能提升了10倍以上,存储空间也节省了90%。

好了,这三种索引的脾性你应该心里有数了。没有银弹,关键是对症下药。下次建索引时,先停下来想一想:你的查询长什么样?你的数据长什么样?别一上来就建个B树完事。