bigywater.tech
MongoDB · 48

索引占多大:前缀压缩与字段长度

一个索引到底占多大?字段长度和取值分布怎么影响它?前缀压缩有多重要?这篇用同一个 20 万文档的集合建 12 个不同字段的索引逐个量。

79.8 对 68.2 MB
12 个单字段索引合计与数据 storageSize
3.4 倍
随机 32 字符串索引相对顺序递增 32 字符串索引的大小
5.0 倍
关掉前缀压缩后,前 52 个字符相同的字符串索引变大的倍数

每条目多大

实测 · 本机执行输出
  字段      值的类型                        值的 BSON 字节          索引大小       每条目字节
  i32     int32 递增                           4.0     1,986,560         9.9
  i64     int64                              8.0     2,912,256        14.6
  dbl     double 随机                          8.0     3,575,808        17.9
  oid     ObjectId                          12.0     1,789,952         8.9
  seq32   32 字符,按顺序递增                       37.0     2,396,160        12.0
  rnd32   32 字符随机十六进制                       37.0     8,056,832        40.3
  s8      8 字符随机                            13.0     2,695,168        13.5
  s16     16 字符随机                           21.0     4,485,120        22.4
  s64     64 字符随机                           69.0    15,429,632        77.1
  s128    128 字符随机                         133.0    30,117,888       150.6
  pre     60 字符,前 52 个相同                    65.0     3,080,192        15.4
  cat     4 个取值的枚举                           9.2     1,077,248         5.4
  _id_ (int 递增)                                   2,207,744        11.0
  数据本身 storageSize 68,308,992;所有索引合计 79,810,560

枚举 5.4 字节、ObjectId 8.9、int32 9.9、递增字符串 12.0、随机 32 字符 40.3、随机 128 字符 150.6 字节。字段类型和取值分布共同决定大小。

前缀压缩

实测 · 本机执行输出
  seq32 2,396,160 字节;rnd32 8,056,832 字节(是顺序递增的 3.4 倍)
  pre(60 字符,前缀 52 相同)3,080,192 字节;s8(8 字符随机)2,695,168 字节;s64(64 字符随机)15,429,632 字节

WiredTiger 默认对索引做前缀压缩:顺序递增的字符串索引只有同样长度随机字符串的 1/3.4;前 52 个字符相同的字符串也压得很好。

长度

实测 · 本机执行输出
    8 字符:每条目 13.5 字节
   16 字符:每条目 22.4 字节
   32 字符:每条目 40.3 字节
   64 字符:每条目 77.1 字节
  128 字符:每条目 150.6 字节
  从 8 到 128 字符,每多 1 个字符,每条索引条目平均多 1.14 字节

随机字符串每多一个字符,每条索引条目平均多约 1.14 字节;长字段上的索引非常大。

关掉前缀压缩

实测 · 本机执行输出
  seq32_1:有前缀压缩(默认)2,396,160 字节;prefix_compression=false 8,736,768 字节(是默认的 3.6 倍)
  pre_1:有前缀压缩(默认)3,080,192 字节;prefix_compression=false 15,261,696 字节(是默认的 5.0 倍)

建索引时指定 prefix_compression=false,seq32 索引变大 3.6 倍,pre 索引变大 5.0 倍。

复合与单字段

实测 · 本机执行输出
  复合 {cat, rnd32} 8,458,240 字节;单字段 cat 1,077,248 + rnd32 8,056,832 = 9,134,080 字节

{cat, rnd32} 复合索引比 cat 与 rnd32 两个单字段索引合计小约 7%。

线性增长

实测 · 本机执行输出
   50,000 个文档:2,035,712 字节(每条目 40.7 字节)
  100,000 个文档:4,046,848 字节(每条目 40.5 字节)
  200,000 个文档:8,056,832 字节(每条目 40.3 字节)

索引大小随文档数线性增长,每条目字节数基本不变。

分步演示

索引大小
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / MongoDB 9.0.2(Homebrew 的 mongod、mongos)/ mongosh 2.12.0 / pymongo 4.18.3;每个实验在临时目录里起全新的 mongod(独立 dbpath,端口 9900 以上,只监听 127.0.0.1,WiredTiger 缓存 0.25 GB),需要副本集或分片集群时在本机起多个进程;命令输出来自真实的 mongosh,批量写入、计时与多线程用 pymongo;计时用 time.perf_counter,数字每次运行会有小幅抖动,ObjectId、时间戳等每次运行都不同。20 万个文档,所有字段由固定种子生成(ObjectId 除外);索引大小来自 fsync 后的 collStats
    • 没有验证:索引在碎片(大量更新/删除)后的膨胀;compact 对索引大小的影响;不同 WiredTiger 内存页大小;SBE 对索引键压缩的无关性;multikey、哈希、地理索引的大小对比(见各自的文章);索引在内存里的占用与缓存的关系
    京ICP备2026067502号-1京公网安备11010502063487号