IndexedDB索引查询天然有序,无需内存排序;而全量读取后JS中filter/sort会消耗内存且性能陡增。索引基于B+树,openCursor可直接按序遍历;未建索引或字段不匹配时被迫内存排序,导致主线程阻塞。

IndexedDB 的索引查询天然有序,无需额外内存排序;而绕过索引、全量读取后在 JS 中 filter/sort,会触发主线程遍历与排序,消耗内存且性能随数据量陡增。
索引查询:按序组织,查即得序
IndexedDB 的索引底层基于 B+ 树或类似有序结构,数据插入时已按索引字段自动排序。只要查询使用对应索引(如 by-status-time),index.openCursor() 就能直接按物理顺序遍历,无需额外计算。
- 升序查询:
index.openCursor(IDBKeyRange.bound('a', 'z'))按字典序连续返回 - 降序查询:
index.openCursor(null, 'prev')从末尾反向游走,同样 O(1) 每次移动 - 复合索引排序:
['status', 'createdAt']索引可直接支持{ status: 'active', createdAt: { $gte: t } }类查询,并保持两字段联合排序
内存排序:全量加载 + JS 运行时开销
若未建索引,或错误地先用 objectStore.getAll() 拿到全部记录再 .filter().sort(),就会:
- 一次性将所有对象反序列化进内存(可能数十 MB)
- JS 引擎执行
Array.sort(),时间复杂度 O(n log n),10 万条数据排序常耗时 200ms+ - 主线程阻塞,页面响应延迟,尤其在低端设备上明显卡顿
- 无法流式处理——必须等全部数据加载完才能开始排序
什么时候会退化为内存排序?
不是 IndexedDB 自身做内存排序,而是开发者误用导致 JS 层被迫排序。典型场景包括:
- 没在
onupgradeneeded中创建对应索引,查询时只能全表扫描 - 排序字段与索引字段不一致,例如索引是
['name', 'age'],却按age单独升序查——无法利用索引顺序 - 对多值字段(如数组)建了多键索引,但排序条件未覆盖索引前缀,触发游标后仍需 JS 二次筛选
如何确保走索引排序?
关键看 openCursor 是否绑定在 index 上,且 range 和方向匹配索引结构:
- 单字段索引
by-name→ 支持index.openCursor(IDBKeyRange.only('Alice'))或index.openCursor()全遍历 - 复合索引
by-type-updated(['type', 'updatedAt'])→ 支持index.openCursor(IDBKeyRange.bound(['post', t1], ['post', t2])),结果天然按updatedAt排序 - 避免
objectStore.index('xxx').get(key)后再对结果数组调sort()——get 只返回单条,无排序意义

















