# DBX Web 运行内存功能排查报告 日期:2026-06-11 ## 结论 已将网页版 DBX 的访问密码设置为 `test`,并通过接口验证登录成功。当前可访问地址: ```text http://127.0.0.1:5173/login ``` 本次用独立 Chrome profile 打开 DBX Web,创建 5 万行 SQLite 测试库,逐项触发主要功能并采集运行内存。当前测到最占运行内存的功能是: 1. 数据对比 Data Compare:优化前后端 `dbx-web` RSS 从约 213 MiB 峰值升到约 496 MiB,是原始基线中最高。 2. 查询图表 QueryChart:在 5 万行结果上打开图表后,前端 JS heap 升到约 109 MiB,Chrome renderer 峰值约 567 MiB。 3. 查询结果 DataGrid:5 万行、12 列查询结果进入 DataGrid 后,前端 JS heap 约 78 MiB,Chrome renderer 约 480 MiB,后端 RSS 约 194 MiB。 4. 驱动管理 Driver Store:DOM 节点明显增加,但 JS heap 被 GC 后下降,未表现为主要内存来源。 5. 空数据对比对话框:只打开对话框增量很小,不是内存大头;真正占用来自执行对比。 第一轮已优化 Data Compare 后端内存路径:同样 50,000 vs 49,649 行场景下,`dbx-web` RSS 峰值从 507,504 KiB 降到 239,696 KiB,下降约 53%;接口输出计数、SQL 数量和响应大小保持一致。 开发服务器 Vite 本身 RSS 很高,后续一度到约 1.1-1.2 GiB。这是 dev/HMR 工具链占用,不属于某个业务功能,但会显著抬高当前机器的总内存占用。 ## 密码重置 认证实现: - 前端登录接口:`/api/auth/login` - 初始设置接口:`/api/auth/setup` - 后端密码存储:`~/.dbx-web/dbx.db` 的 `app_settings.settings_json.password_hash` - `DBX_PASSWORD` 环境变量会覆盖数据库密码,但本次没有用环境变量覆盖,而是走 `/api/auth/setup` 持久化设置。 验证结果: ```text POST /api/auth/setup {"password":"test"} -> 200 OK POST /api/auth/login {"password":"test"} -> 200 OK GET /api/auth/check with cookie -> {"authenticated":true,"required":true,"setup_required":false} ``` ## 测试环境 运行进程: | 组件 | 地址 / 进程 | 说明 | | --- | --- | --- | | Web 前端 | `http://127.0.0.1:5173` | 已存在的 Vite dev server | | Web 后端 | `target/debug/dbx-web`,端口 `4224` | 本次启动,用于 API 和认证 | | 测量浏览器 | Chrome 独立 profile:`/tmp/dbx-runtime-chrome-profile` | 只打开 DBX 页面,避免混入日常 Chrome tab | 测试数据: | 对象 | 规模 | | --- | ---: | | SQLite 文件 | `/tmp/dbx-runtime-memory-probe.sqlite` | | DBX 连接名 | `Runtime Memory SQLite` | | `runtime_probe` | 50,000 行,12 列 | | `runtime_probe_target` | 49,649 行,12 列 | | DataGrid page size | 50,000 | | DataGrid render mode | Canvas | ## 测量方法 采集方式: - Chrome DevTools Protocol `Performance.getMetrics` - `JSHeapUsedSize` - `JSHeapTotalSize` - DOM node count - macOS `ps` - 独立 Chrome profile 总 RSS - Chrome renderer RSS - Vite RSS - `dbx-web` RSS - 数据对比 API 额外用 50ms 间隔采样 `dbx-web` RSS 峰值。 注意: - JS heap 是前端页面 heap,不包含浏览器共享库、GPU、网络进程等。 - Chrome renderer RSS 更接近页面实际进程内存,但仍包含渲染器基础开销。 - Vite 是开发工具链,不应归因到业务功能。 - 数据对比 API 测到的是后端执行峰值;本轮没有自动填完整数据对比对话框并渲染 diff 明细。 ## 运行内存记录 单位说明: - JS heap:MiB - RSS:KiB,括号内为约 MiB | 场景 | JS heap used | Chrome renderer RSS | Chrome profile 总 RSS | `dbx-web` RSS | Vite RSS | 备注 | | --- | ---: | ---: | ---: | ---: | ---: | --- | | 登录页 | 13.30 MiB | 未拆分 | 906,576 KiB(885 MiB) | 未启动/低 | 475,200 KiB(464 MiB) | 登录页 DOM 约 255 | | 登录后主界面 | 25.12 MiB | 未拆分 | 961,760 KiB(939 MiB) | 72,688 KiB(71 MiB) | 481,376 KiB(470 MiB) | 已加载连接列表 | | 打开查询编辑器 | 25.86 MiB | 未拆分 | 未记录 | 未记录 | 未记录 | CodeMirror 出现,增量很小 | | 设置 page size 后刷新 | 31.83 MiB | 408,608 KiB(399 MiB) | 1,003,440 KiB(980 MiB) | 54,048 KiB(53 MiB) | 1,224,272 KiB(1,196 MiB) | Dev server RSS 明显上升 | | 填入 SQL | 34.94 MiB | 414,144 KiB(404 MiB) | 1,016,384 KiB(993 MiB) | 54,720 KiB(53 MiB) | 1,224,272 KiB(1,196 MiB) | 编辑器文本变化 | | DataGrid 5 万行结果 | 77.98 MiB | 491,440 KiB(480 MiB) | 1,089,552 KiB(1,064 MiB) | 198,448 KiB(194 MiB) | 1,249,856 KiB(1,221 MiB) | 50,000 行、12 列、Canvas | | 图表前,GC 后 | 61.15 MiB | 443,040 KiB(433 MiB) | 1,046,128 KiB(1,022 MiB) | 198,448 KiB(194 MiB) | 1,161,296 KiB(1,134 MiB) | DataGrid 结果仍在 | | QueryChart 5 秒 | 109.77 MiB | 580,976 KiB(567 MiB) | 1,185,408 KiB(1,158 MiB) | 198,448 KiB(194 MiB) | 1,172,096 KiB(1,145 MiB) | ECharts + series 数据峰值 | | QueryChart 10 秒 | 108.74 MiB | 524,160 KiB(512 MiB) | 1,128,544 KiB(1,102 MiB) | 198,448 KiB(194 MiB) | 1,172,096 KiB(1,145 MiB) | 图表稳定后 | | 空数据对比对话框 | 110.72 MiB | 531,520 KiB(519 MiB) | 1,141,376 KiB(1,115 MiB) | 198,448 KiB(194 MiB) | 1,187,120 KiB(1,159 MiB) | 只打开弹窗,增量小 | | Data Compare API | 不适用 | 不适用 | 不适用 | 峰值 507,504 KiB(496 MiB) | 不适用 | 50k vs 49,649 行,两表对比 | | 驱动管理 | 67.49 MiB | 535,072 KiB(522 MiB) | 1,145,696 KiB(1,119 MiB) | 478,928 KiB(468 MiB) | 1,188,624 KiB(1,161 MiB) | DOM 到 1,157,但 JS heap 被 GC | ## 数据对比明细 ### 优化前基线 接口: ```text POST /api/data-compare/prepare-from-tables ``` 参数: ```text source table: main.runtime_probe target table: main.runtime_probe_target key columns: id fetch batch size: 5000 ``` 结果: | 指标 | 值 | | --- | ---: | | 耗时 | 842 ms | | `dbx-web` RSS before | 217,904 KiB(213 MiB) | | `dbx-web` RSS peak | 507,504 KiB(496 MiB) | | `dbx-web` RSS after | 472,416 KiB(461 MiB) | | 响应大小 | 10,291,638 bytes | | source rows | 50,000 | | target rows | 49,649 | | added | 1,351 | | removed | 1,000 | | modified | 4,865 | | sync statements | 7,216 | | sync SQL 大小 | 1,537,738 bytes | 判断:数据对比是本轮最高内存来源。原因是后端会同时持有两边 rows、HashMap、diff、sync statements 和完整 sync SQL;请求结束后 RSS 也没有立刻回到对比前。 ### 第一轮优化复测 代码改动: - `crates/dbx-core/src/data_compare.rs` - 对比中间态从“每一行都转成 `HashMap`”改为“按列索引保存 `Vec`,只在 added/removed/modified 输出时组装 HashMap”。 - 去掉 `prepare_data_compare` 和缺目标表路径里的 `DataCompareResult` clone。 - 单元格比较改为借用比较,只有确认为变化时才 clone 到返回结果。 - 同步计划生成改为内部借用 diff,公共 API 和返回字段不变。 复测结果: | 指标 | 优化前 | 优化后 | 变化 | | --- | ---: | ---: | ---: | | 耗时 | 842 ms | 942 ms | +100 ms | | `dbx-web` RSS before | 217,904 KiB(213 MiB) | 65,168 KiB(64 MiB) | 启动基线更干净 | | `dbx-web` RSS peak | 507,504 KiB(496 MiB) | 239,696 KiB(234 MiB) | -267,808 KiB(约 -53%) | | `dbx-web` RSS after | 472,416 KiB(461 MiB) | 233,840 KiB(228 MiB) | -238,576 KiB | | 响应大小 | 10,291,638 bytes | 10,291,638 bytes | 不变 | | added / removed / modified | 1,351 / 1,000 / 4,865 | 1,351 / 1,000 / 4,865 | 不变 | | sync statements | 7,216 | 7,216 | 不变 | | sync SQL 大小 | 1,537,738 bytes | 1,537,738 bytes | 不变 | 结论:这次优化不改变接口协议和功能结果,主要降低后端比较过程的峰值和结束后的 RSS 留存。剩余内存主要来自必须返回给前端的 diff 详情、`syncStatements` 数组、完整 `syncSql` 字符串以及约 10 MB JSON 响应。 ## 功能排名 ### 1. 数据对比 Data Compare 原始基线最高。50k 级别两表对比让后端 RSS 峰值接近 496 MiB,且结束后仍约 461 MiB。第一轮优化后,同场景峰值降到约 234 MiB,结束后约 228 MiB。 主要来源: - 源表 rows + 目标表 rows - diff 明细对象 - sync statements - joined sync SQL - 约 10 MB JSON 响应 建议: - 进一步对比可改为主键有序 merge,不一次性保留两边全量 rows。 - diff 明细分页,默认只返回计数和样例。 - sync SQL 按需生成或流式下载。 - 大表对比增加行数阈值和用户确认。 ### 2. QueryChart 本轮最高的前端内存增量。基于同一份 5 万行查询结果,打开图表后 JS heap 稳定在约 109 MiB,较图表前增加约 48 MiB;renderer RSS 峰值增加约 138 MiB。 主要来源: - ECharts / vue-echarts 运行时 - `xData = rows.map(...)` - 每个 Y 列再生成一份 series data - Canvas 图表内部缓存 建议: - 图表默认采样或限制最大点数,例如 5,000。 - 多 Y 轴列时显示数据点数量并要求确认。 - 数值列识别用抽样,不扫描全部 rows。 ### 3. 查询结果 DataGrid 5 万行、12 列进入 DataGrid 后,JS heap 约 78 MiB,较填 SQL 后增加约 43 MiB;后端 RSS 也从约 53 MiB 增至约 194 MiB。 主要来源: - 查询结果 rows - DataGrid 显示索引和派生结构 - Canvas 渲染状态 - 后端查询结果构造和 JSON 序列化 建议: - 默认 page size 不要轻易升到 50,000。 - DataGrid 派生数组按可视范围懒生成。 - 导出和大结果操作走 streaming。 - 对大结果显示明确内存提示。 ### 4. 驱动管理 驱动管理页面 DOM 节点从 426 增到 1,157,但 JS heap 因 GC 从约 112 MiB 降到约 67 MiB,说明它不是当前主要内存来源。它主要增加 DOM 和列表渲染,不像 DataGrid/Chart/DataCompare 那样复制大数据。 ### 5. 空数据对比对话框 只打开对话框时 JS heap 从约 109 MiB 到约 111 MiB,增量很小。风险不在弹窗本身,而在点击“开始比较数据”后的后端对比和 diff 明细。 ## 未覆盖功能 本轮没有实测以下功能,因为当前环境没有对应服务或没有构造完整数据流: - Redis Key Browser - Mongo 文档浏览 - 数据传输 - SQL 文件执行 - 导出下载全流程 - ER Diagram / Schema Diff 大 schema 场景 - AI Assistant 长对话 这些功能仍可能在真实环境中占用较高内存,尤其是 Redis 全量 key、Mongo 宽文档表格视图、导出聚合和大 schema diff。代码风险分析见同目录的 `memory-usage-audit.md`。 ## 当前最值得优化的点 1. 继续优化 Data Compare 返回体:第一轮已降峰值,下一步是 diff 分页、SQL 按需生成,减少必须返回给前端的数据量。 2. 限制 QueryChart 数据点:图表对大结果集的前端复制非常明显。 3. 限制 DataGrid 大 page size:50,000 行能明显抬高前端和后端内存。 4. 把 Vite/dev 内存与业务内存分开看:当前开发模式下 Vite RSS 本身可超过 1 GiB,生产 Tauri 或生产 Web 包需要另测。