perf(P1): 批量插入性能悬崖 — insert 循环内逐行 prefetchKeys(每行 await drainChain 排空后台链),compaction 在链上数秒时每行阻塞数秒 → kv 后端 10 万行插入 353s;改为批级预加载本批 PK 一次,实测 353s→12.5s(28 倍)/ opfs 25s;新增 kv/opfs 双后端 10 万行回归(性能护栏+索引完整+崩溃恢复),aria-cache 测试同步适配显式 flush
This commit is contained in:
@@ -290,4 +290,83 @@ describe('AriaEngine — 生产负载验证', () => {
|
||||
expect(await engine2.find('big', { table: 'big', where: { tag: 't3' } })).toHaveLength(5000);
|
||||
await engine2.close();
|
||||
}, 180000);
|
||||
|
||||
it('10 万行 kv 后端(含索引):完整查询 + 崩溃恢复(v0.6.1-perf 回归)', async () => {
|
||||
const dbName = uniqueDB();
|
||||
const engine = new AriaEngine({
|
||||
storageBackend: 'kv',
|
||||
memtableSizeThreshold: 512 * 1024,
|
||||
checkpointInterval: 30000,
|
||||
walSyncMode: 'full',
|
||||
});
|
||||
await engine.open(dbName, 1);
|
||||
await engine.createTable(SCHEMA());
|
||||
|
||||
const TOTAL = 100000;
|
||||
const t0 = Date.now();
|
||||
for (let batch = 0; batch < TOTAL / 1000; batch++) {
|
||||
const rows = [] as Record<string, unknown>[];
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const idx = batch * 1000 + i;
|
||||
rows.push({ id: `k${idx}`, val: idx, tag: `t${idx % 10}`, name: `User${idx}` });
|
||||
}
|
||||
await engine.insert('big', rows);
|
||||
}
|
||||
const insertMs = Date.now() - t0;
|
||||
// 性能护栏:修复前 353s(batch 32 起每批 8~11s 性能悬崖),修复后 <30s
|
||||
console.log(`10万行 kv 插入耗时: ${insertMs}ms`);
|
||||
expect(insertMs).toBeLessThan(60000);
|
||||
expect(await engine.count('big')).toBe(TOTAL);
|
||||
|
||||
// 全部 10 个 tag 索引查询完整
|
||||
for (let t = 0; t < 10; t++) {
|
||||
const viaIdx = await engine.find('big', { table: 'big', where: { tag: `t${t}` } });
|
||||
expect(viaIdx.length).toBe(10000);
|
||||
}
|
||||
|
||||
// 崩溃恢复
|
||||
await (engine as any).backend.close();
|
||||
(engine as any).opened = false;
|
||||
const engine2 = new AriaEngine({
|
||||
storageBackend: 'kv',
|
||||
memtableSizeThreshold: 512 * 1024,
|
||||
checkpointInterval: 30000,
|
||||
walSyncMode: 'full',
|
||||
});
|
||||
await engine2.open(dbName, 1);
|
||||
expect(await engine2.count('big')).toBe(TOTAL);
|
||||
expect(await engine2.find('big', { table: 'big', where: { tag: 't7' } })).toHaveLength(10000);
|
||||
await engine2.close();
|
||||
}, 180000);
|
||||
|
||||
it('10 万行 opfs 后端(含索引):完整查询(v0.6.1-perf 回归)', async () => {
|
||||
const engine = new AriaEngine({
|
||||
storageBackend: 'opfs',
|
||||
memtableSizeThreshold: 512 * 1024,
|
||||
checkpointInterval: 30000,
|
||||
walSyncMode: 'full',
|
||||
});
|
||||
await engine.open(uniqueDB(), 1);
|
||||
await engine.createTable(SCHEMA());
|
||||
|
||||
const TOTAL = 100000;
|
||||
const t0 = Date.now();
|
||||
for (let batch = 0; batch < TOTAL / 1000; batch++) {
|
||||
const rows = [] as Record<string, unknown>[];
|
||||
for (let i = 0; i < 1000; i++) {
|
||||
const idx = batch * 1000 + i;
|
||||
rows.push({ id: `k${idx}`, val: idx, tag: `t${idx % 10}`, name: `User${idx}` });
|
||||
}
|
||||
await engine.insert('big', rows);
|
||||
}
|
||||
const insertMs = Date.now() - t0;
|
||||
console.log(`10万行 opfs 插入耗时: ${insertMs}ms`);
|
||||
expect(insertMs).toBeLessThan(90000);
|
||||
expect(await engine.count('big')).toBe(TOTAL);
|
||||
for (let t = 0; t < 10; t++) {
|
||||
const viaIdx = await engine.find('big', { table: 'big', where: { tag: `t${t}` } });
|
||||
expect(viaIdx.length).toBe(10000);
|
||||
}
|
||||
await engine.close();
|
||||
}, 180000);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user