存储索引概述

大家好,我是老张,干数据库调优这行快十年了。今天咱们聊聊索引——这个看似基础、实则门道极深的话题。说实话,我见过不少开发同学,写SQL很溜,但一提到索引就两眼一抹黑。嗯,这节课咱们就把索引的底裤扒干净。

1.1 索引是什么?——我的理解

索引,说白了就是数据的“目录”。你想想看,一本500页的书,你想找“哈希索引”这个关键词,没有目录你得一页一页翻,有了目录直接翻到第238页。数据库里也是一样,全表扫描就像翻书,索引就是那个目录。

我记得刚入行时,一个同事跟我说“索引就是B树”。当时我似懂非懂,后来才明白,索引不只B树,还有哈希、位图,甚至还有全文索引、空间索引。但最常用的,还是今天要讲的这三兄弟。

索引本质:一种以空间换时间的数据结构,通过额外的存储来加速数据检索。

1.2 索引到底解决了什么问题?

我把它总结为三点:

  • 减少磁盘I/O:不用每次都把整张表读进内存。一个好的索引能把随机I/O变成顺序I/O。
  • 避免排序:如果查询要排序,索引本身就有序,直接拿数据就行。
  • 保证唯一性:主键索引、唯一索引能直接从逻辑上避免重复数据。

当然,索引不是万能的。我曾经在一个项目里,给一张日增百万记录的表建了十几个索引,结果插入速度慢到怀疑人生。所以,懂索引的人,知道什么时候该建,什么时候不该建。

1.3 三大主流索引类型

咱们一个一个聊。

1.3.1 B树索引

B树(Balanced Tree)是最常见的索引结构。几乎所有关系型数据库的默认索引都是B+树,这玩意是B树的变种。

特点:

  • 所有叶子节点在同一层,保证查询稳定(稳定在O(log n))。
  • 叶子节点用指针串成链表,方便范围查询(大于、小于、between)。
  • 非叶子节点只存键值,不存数据,所以树很矮。

适用场景:范围查询、排序、前缀匹配。比如 WHERE age BETWEEN 20 AND 30,B树索引非常高效。

我曾经帮一个电商系统调优,订单表按月查询特别慢。建了一个B树索引在order_date上,查询时间从12秒降到0.2秒。那种感觉,很爽。

1.3.2 哈希索引

哈希索引(Hash Index)用哈希函数把键值映射到槽位。你给它一个值,它直接算出位置,一步到位。理论上时间复杂度O(1)。

但有一个大坑——哈希索引不支持范围查询。因为哈希函数把值打乱了,WHERE id > 100这种查询,它只能全扫。还有就是哈希冲突,不同键算出同一个槽位,就得链式处理,性能会退化。

避坑指南:我曾经在一个用户登录系统里,看到有人对用户名建了哈希索引。用户登录查单条记录确实快,但后来需求变了,要查“所有注册时间在昨天的用户”,结果哈希索引完全用不上,只能全表扫描。所以哈希索引只适合等值查询,比如WHERE user_id = 123。

适用场景:精确匹配,键值唯一或接近唯一。比如MySQL的Memory引擎默认使用哈希索引,适合临时表、缓存表。

1.3.3 位图索引

位图索引(Bitmap Index)用二进制位表示某个值是否存在。每个键值对应一个位图,位图的长度就是表的行数。如果某行有该值,对应位为1,否则为0。

特点:

  • 空间压缩:对于低基数列(比如性别、状态),位图非常省空间。
  • 快速交并:两个位图做AND/OR运算比B树快得多,尤其适合数据仓库里的组合查询。

但位图索引在高并发写入场景下是噩梦。因为每次更新一行,可能要修改多个位图。我记得在Oracle数据仓库项目里,给一个分区表建了位图索引,跑ETL时锁冲突严重,后来改成了B树。

适用场景:数据仓库、OLAP、低基数(比如性别、省份、状态)且读多写少的表。

下面这张表对比了三种索引的核心差异,干活的时候常回头看看:

特性 B树索引 哈希索引 位图索引
典型数据结构 B+树 哈希表 位图数组
查询时间复杂度 O(log n) O(1)(平均) O(列基数 × 行数)(构建)
支持范围查询 是 否 部分(需位图运算)
适合基数 高基数 高基数 低基数
写入性能 良好 好 差(高并发锁)
典型数据库 MySQL InnoDB, PostgreSQL MySQL Memory, Redis Oracle, Greenplum

感觉清晰了吗?我再用一张图帮你理一下思路:

索引选择决策图 索引 B树索引 哈希索引 位图索引 范围查询 √ 高基数 √ 写入良好 等值查询 O(1) 不支持范围 适合精确匹配 低基数 √ 位运算快 写入锁严重 适用场景 OLTP范围查询 排序、前缀匹配 适用场景 等值唯一查询 缓存、内存表 适用场景 数据仓库OLAP 低基数统计

选型小贴士:先看你的查询模式——等值多选哈希,范围多选B树,低基数多条件组合选位图。当然,实际中经常混用,比如MySQL InnoDB主键用B树,但也能用自适应哈希索引(AHI)做二级加速。

1.4 小结

这一章我们聊了索引的定义、作用和三大类型。总结一下:

  • 索引是加速数据访问的数据结构,用空间换时间。
  • B树最适合范围查询,哈希适合等值查询,位图适合低基数组合分析。
  • 没有银弹,别给所有列都建索引,否则写入会崩。

我个人习惯在接手一个新系统时,先通过慢查询日志找出热点SQL,再根据查询类型反推应该建哪种索引。你看,学索引不是为了背概念,而是为了在做决定时有依据。好了,这章就到这,希望下次你在建索引时能想起今天的内容。