Files
t8y2--dbx/docs/performance/runtime-memory-audit.md
2026-07-13 13:09:14 +08:00

11 KiB
Raw Permalink Blame History

DBX Web 运行内存功能排查报告

日期:2026-06-11

结论

已将网页版 DBX 的访问密码设置为 test,并通过接口验证登录成功。当前可访问地址:

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 MiBChrome renderer 峰值约 567 MiB。
  3. 查询结果 DataGrid:5 万行、12 列查询结果进入 DataGrid 后,前端 JS heap 约 78 MiBChrome renderer 约 480 MiB,后端 RSS 约 194 MiB。
  4. 驱动管理 Driver StoreDOM 节点明显增加,但 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.dbapp_settings.settings_json.password_hash
  • DBX_PASSWORD 环境变量会覆盖数据库密码,但本次没有用环境变量覆盖,而是走 /api/auth/setup 持久化设置。

验证结果:

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 heapMiB
  • RSSKiB,括号内为约 MiB
场景 JS heap used Chrome renderer RSS Chrome profile 总 RSS dbx-web RSS Vite RSS 备注
登录页 13.30 MiB 未拆分 906,576 KiB885 MiB 未启动/低 475,200 KiB464 MiB 登录页 DOM 约 255
登录后主界面 25.12 MiB 未拆分 961,760 KiB939 MiB 72,688 KiB71 MiB 481,376 KiB470 MiB 已加载连接列表
打开查询编辑器 25.86 MiB 未拆分 未记录 未记录 未记录 CodeMirror 出现,增量很小
设置 page size 后刷新 31.83 MiB 408,608 KiB399 MiB 1,003,440 KiB980 MiB 54,048 KiB53 MiB 1,224,272 KiB1,196 MiB Dev server RSS 明显上升
填入 SQL 34.94 MiB 414,144 KiB404 MiB 1,016,384 KiB993 MiB 54,720 KiB53 MiB 1,224,272 KiB1,196 MiB 编辑器文本变化
DataGrid 5 万行结果 77.98 MiB 491,440 KiB480 MiB 1,089,552 KiB1,064 MiB 198,448 KiB194 MiB 1,249,856 KiB1,221 MiB 50,000 行、12 列、Canvas
图表前,GC 后 61.15 MiB 443,040 KiB433 MiB 1,046,128 KiB1,022 MiB 198,448 KiB194 MiB 1,161,296 KiB1,134 MiB DataGrid 结果仍在
QueryChart 5 秒 109.77 MiB 580,976 KiB567 MiB 1,185,408 KiB1,158 MiB 198,448 KiB194 MiB 1,172,096 KiB1,145 MiB ECharts + series 数据峰值
QueryChart 10 秒 108.74 MiB 524,160 KiB512 MiB 1,128,544 KiB1,102 MiB 198,448 KiB194 MiB 1,172,096 KiB1,145 MiB 图表稳定后
空数据对比对话框 110.72 MiB 531,520 KiB519 MiB 1,141,376 KiB1,115 MiB 198,448 KiB194 MiB 1,187,120 KiB1,159 MiB 只打开弹窗,增量小
Data Compare API 不适用 不适用 不适用 峰值 507,504 KiB496 MiB 不适用 50k vs 49,649 行,两表对比
驱动管理 67.49 MiB 535,072 KiB522 MiB 1,145,696 KiB1,119 MiB 478,928 KiB468 MiB 1,188,624 KiB1,161 MiB DOM 到 1,157,但 JS heap 被 GC

数据对比明细

优化前基线

接口:

POST /api/data-compare/prepare-from-tables

参数:

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 KiB213 MiB
dbx-web RSS peak 507,504 KiB496 MiB
dbx-web RSS after 472,416 KiB461 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<String, Value>”改为“按列索引保存 Vec<Value>,只在 added/removed/modified 输出时组装 HashMap”。
  • 去掉 prepare_data_compare 和缺目标表路径里的 DataCompareResult clone。
  • 单元格比较改为借用比较,只有确认为变化时才 clone 到返回结果。
  • 同步计划生成改为内部借用 diff,公共 API 和返回字段不变。

复测结果:

指标 优化前 优化后 变化
耗时 842 ms 942 ms +100 ms
dbx-web RSS before 217,904 KiB213 MiB 65,168 KiB64 MiB 启动基线更干净
dbx-web RSS peak 507,504 KiB496 MiB 239,696 KiB234 MiB -267,808 KiB(约 -53%
dbx-web RSS after 472,416 KiB461 MiB 233,840 KiB228 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 MiBrenderer 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 size50,000 行能明显抬高前端和后端内存。
  4. 把 Vite/dev 内存与业务内存分开看:当前开发模式下 Vite RSS 本身可超过 1 GiB,生产 Tauri 或生产 Web 包需要另测。