IndexedDB索引是实现高效条件查询的核心机制,通过为非主键字段创建排序副键表来避免全表扫描,支持精确匹配、范围查询、排序及多值索引,需在onupgradeneeded中定义且不可动态添加。

IndexedDB 的索引(Index)是实现高效条件查询的核心机制,它允许你绕过主键(keyPath)直接按其他字段快速查找数据,避免全表扫描。
为什么需要索引?
对象存储(Object Store)默认只按主键(如 id)有序存储。若想按 status、createdAt 或 userId 查询,不建索引就得遍历所有记录——数据量稍大就明显卡顿。索引本质是一份按指定字段排序的“副键表”,支持范围查询、排序和去重。
创建索引:在 upgrade 时定义
索引必须在数据库版本升级(onupgradeneeded)中创建,不能运行时动态添加。关键参数包括名称、路径(字段名)、选项(是否唯一、是否多条目):
request.onupgradeneeded = (event) => {
const db = event.target.result;
const store = db.createObjectStore('tasks', { keyPath: 'id' });
// 按 status 查询:普通索引(允许重复值)
store.createIndex('by-status', 'status', { unique: false });
// 按 email 查询:唯一索引(如用户邮箱不可重复)
store.createIndex('by-email', 'email', { unique: true });
// 按时间范围查询:支持 from/to 范围扫描
store.createIndex('by-date', 'createdAt', { unique: false });
// 多值索引:当字段是数组时,为每个元素建一条索引项
store.createIndex('by-tag', 'tags', { unique: false, multiEntry: true });
};
用索引执行条件查询
拿到索引后,调用 index.openCursor() 或 index.get() 等方法,传入 IDBKeyRange 构造查询范围:
立即学习“Java免费学习笔记(深入)”;
-
精确匹配:
IDBKeyRange.only('done')→ 查所有 status === 'done' 的记录 -
范围查询:
IDBKeyRange.lowerBound('2023-01-01')→ createdAt ≥ '2023-01-01' -
区间查询:
IDBKeyRange.bound('2023-01-01', '2023-12-31', true, true)→ 开区间(不含端点) -
前缀匹配(字符串):
IDBKeyRange.bound('abc', 'abd', false, true)→ 字段以 'abc' 开头
示例:查所有已完成任务并按时间倒序返回
const transaction = db.transaction(['tasks'], 'readonly');
const store = transaction.objectStore('tasks');
const index = store.index('by-status');
// 先定位到 status === 'done' 的起始位置,再反向遍历
const range = IDBKeyRange.only('done');
const cursorRequest = index.openCursor(range, 'prev'); // 'prev' 表示倒序
cursorRequest.onsuccess = (event) => {
const cursor = event.target.result;
if (cursor) {
console.log(cursor.value); // 完整对象
cursor.continue(); // 继续下一条
}
};
复合条件与性能提示
IndexedDB 原生不支持多字段联合索引(如 status + priority),但可通过以下方式逼近:
- 把多个字段拼成一个复合键:如
indexKey = `${status}-${priority}`,再建索引;查询时用IDBKeyRange.bound('done-1', 'done-2') - 先用索引快速缩小结果集,再在内存中用 JavaScript 过滤次要条件(适合二级条件筛选比例高、数据量不大的场景)
- 避免在索引字段上做函数转换(如
lowercase(name)),索引无法命中;入库前就规范化数据 - 索引越多,写入越慢(每条新增/修改都要更新所有相关索引),按实际查询需求精简索引数量
不复杂但容易忽略。


















