Dexie.js 的批量操作与索引优化
Dexie.js 的批量操作与索引优化
Dexie.js 是一个高性能的 IndexedDB 库,提供了更直观的 API 和更强大的事务支持。针对大数据量的操作,合理使用 批量操作 和 索引优化 可以显著提升数据库的性能。
1. 批量操作
在 IndexedDB 中,每个数据库操作(如插入、更新、删除)都会触发一次事务,而频繁的事务操作可能会导致性能下降。因此,Dexie.js 提供了一些方法来进行批量插入和批量更新,以减少事务的数量并提升性能。
1.1 批量插入(Bulk Insert)
Dexie 提供了 bulkPut()
和 bulkAdd()
方法来进行批量插入:
bulkAdd()
适用于新数据的插入,若存在主键冲突,则会报错。bulkPut()
适用于新增或更新数据,若存在主键冲突,则会更新数据。
示例:批量插入
import Dexie from 'dexie';
// 定义数据库
const db = new Dexie('MyDatabase');
db.version(1).stores({
users: 'id, name, age' // 'id' 是主键,name 和 age 是索引
});
// 批量插入数据
async function insertUsers() {
await db.users.bulkAdd([
{ id: 1, name: 'Alice', age: 25 },
{ id: 2, name: 'Bob', age: 30 },
{ id: 3, name: 'Charlie', age: 28 }
]);
}
insertUsers().catch(console.error);
bulkPut()
示例
如果数据已存在并想要更新:
async function upsertUsers() {
await db.users.bulkPut([
{ id: 1, name: 'Alice', age: 26 }, // 更新 age
{ id: 4, name: 'David', age: 22 } // 新增
]);
}
upsertUsers().catch(console.error);
性能优化:
- 比
db.users.add()
更高效,因为它在一个事务中执行多个操作。 - 避免事务开销,一次性写入多个记录,而不是逐条写入。
1.2 批量更新(Bulk Update)
Dexie 没有 bulkUpdate()
方法,但可以结合 toArray()
和 bulkPut()
实现批量更新。
示例:批量更新
async function updateUsersAge() {
const users = await db.users.where('age').below(30).toArray();
users.forEach(user => {
user.age += 1; // 年龄加1
});
await db.users.bulkPut(users);
}
updateUsersAge().catch(console.error);
性能优化:
- 尽量减少
toArray()
使用,避免加载大量数据到内存。 - 结合索引查询,只筛选需要更新的记录,提高效率。
1.3 批量删除(Bulk Delete)
Dexie 提供了 bulkDelete()
方法来高效删除数据。
示例:批量删除
async function deleteUsers() {
await db.users.bulkDelete([1, 2, 3]); // 通过 ID 删除
}
deleteUsers().catch(console.error);
性能优化:
- 比
db.users.delete(id)
快,因为只执行一个事务。 - 适用于已知 ID 的数据删除,而不是全表扫描。
2. 索引优化
在 IndexedDB 中,索引(Index)可以显著提高查询速度。Dexie.js 允许你在 stores()
方法中定义索引,并支持多字段索引。
2.1 创建索引
索引可以加速 where()
查询。
示例:创建索引
db.version(1).stores({
users: 'id, name, age, [name+age]' // name 和 age 作为索引, name+age 作为复合索引
});
2.2 使用索引查询
如果表有索引,我们可以用 .where()
进行高效查询。
示例:基于索引的查询
async function getUsersByName(name: string) {
const users = await db.users.where('name').equals(name).toArray();
console.log(users);
}
getUsersByName('Alice');
优化点:
- 如果没有索引,Dexie 需要遍历整个表(O(n) 复杂度)。
- 有索引时,查询只需 O(log n) 的时间,提高效率。
2.3 复合索引
当需要查询 多个字段的组合条件 时,可以使用复合索引。
示例:使用复合索引
async function getUsersByNameAndAge(name: string, age: number) {
const users = await db.users.where('[name+age]').equals([name, age]).toArray();
console.log(users);
}
getUsersByNameAndAge('Alice', 26);
优化点:
- 复合索引避免了多次查询和结果合并,提高查询速度。
- 避免
.filter()
过滤大量数据,减少内存使用。
3. 性能优化总结
操作 | 方法 | 优势 |
---|---|---|
批量插入 | bulkAdd() | 更快的插入,避免事务开销 |
批量更新 | bulkPut() | 快速 upsert,减少事务 |
批量删除 | bulkDelete() | 一次性删除多个记录 |
单字段索引 | where('column').equals(value) | 适用于单字段查询 |
复合索引 | where('[column1+column2]').equals([v1, v2]) | 适用于组合查询 |
4. 事务优化
Dexie 允许将多个操作合并到同一个事务中,以减少开销。
示例:使用事务
async function transactionExample() {
await db.transaction('rw', db.users, async () => {
await db.users.bulkPut([
{ id: 5, name: 'Eve', age: 35 },
{ id: 6, name: 'Frank', age: 40 }
]);
await db.users.where('age').below(30).modify(user => {
user.age += 1;
});
});
}
transactionExample().catch(console.error);
性能优化:
- 事务内操作比单独操作更快,避免重复的磁盘 IO。
- 自动回滚,如果事务失败,所有更改都会回滚,避免数据不一致。
5. 结论
- 批量操作(
bulkAdd()
、bulkPut()
、bulkDelete()
)减少事务,提高性能。 - 索引优化(单字段索引、复合索引)显著提高查询速度,避免全表扫描。
- 事务优化(
db.transaction()
)避免重复 IO,加速数据库操作。 - 避免
toArray()
处理大数据量,尽量使用.each()
进行遍历。
如果你的应用涉及大量数据存储和查询,合理使用 Dexie.js 的 批量操作 和 索引优化,可以大幅提升性能! 🚀