跳转到内容
文档

测试手册 — NoSqlStudio Profiler

用于打开、使用和验证新版 Profiler 界面的分步指南。

预计时间: 约 30 分钟
本手册目录

简介

一份分步指南,帮助你打开、使用并验证新版 Profiler 界面。请按顺序从 Step 1 走到结尾。每个步骤都会告诉你该做什么以及会看到什么。你不需要预先了解任何 profiling 知识 — 💡 提示框会在概念出现时立即解释。

如何阅读本手册

每个步骤包含:

  • 操作 — 准确的动作(点击、输入、运行某段脚本)。
  • 查看 — 屏幕上应该发生什么。这就是你的“通过 / 失败”。
  • 原因 — 仅在有助于理解时出现(如果你赶时间可以跳过)。

概念

概念框。 在某个术语出现时立刻解释它。

注意

注意。 一个容易让人困惑的细节。

开始之前

概念

Profiler 是什么

MongoDB 可以保留一本它运行过的所有内容的“日志” — 每条查询、用时多久、是否使用了索引 — 存放在一个名为 system.profile 的集合中。Profiler 界面会打开这本日志并以图形化方式展示:图表、过滤器,甚至是索引建议。

你需要:

  1. 1在最后一次构建之后重启 dev 服务器(否则界面甚至无法加载 — 这正是引起 spacingPx 错误的原因)。
  2. 2一个已连接的 MongoDB 连接。可以是本地、自建,或 Atlas M10+。Atlas M0/M2/M5(免费)上 profiler 被 MongoDB 屏蔽 — 它可以工作,但界面会提示其受限(我们在 Step 41 测试这一点)。
  3. 3数据库用户需要能够运行管理类命令(setProfilingLevelcreateIndex)。一个“database owner”用户即可胜任。

完整走读预计时间:约 30 分钟

阶段 1

准备实验数据库

为了让 Profiler 有内容可显示,我们先创建一个包含大量数据的数据库。

步骤 1

创建 profiler_lab 数据库

操作

在 NoSqlStudio 中打开 Mongo Shell 标签(或 Scratchpad),粘贴下面的脚本并运行。

js·35 linhas
use profiler_lab;
db.dropDatabase();
use profiler_lab;

['orders', 'products', 'customers'].forEach((c) => db.getCollection(c).drop());

function seed(coll, n, gen) {
  const c = db.getCollection(coll);
  let buf = [];
  for (let i = 0; i < n; i++) {
    buf.push(gen(i));
    if (buf.length === 165000) { c.insertMany(buf); buf = []; }
  }
  if (buf.length) c.insertMany(buf);
  print(coll + ': ' + c.countDocuments());
}

const ST = ['pending', 'paid', 'shipped', 'cancelled', 'refunded'];
const RG = ['north', 'south', 'east', 'west'];

seed('orders', 120000, (i) => ({
  orderNo: i, status: ST[i % 5], region: RG[i % 4],
  customerId: (i * 7) % 5000, total: Math.round(Math.random() * 1e5) / 100,
  items: 1 + (i % 8), createdAt: new Date(Date.now() - (i % 90) * 864e5),
  note: 'order line '.repeat(4),
}));
seed('products', 20000, (i) => ({
  sku: 'SKU-' + i, category: ['a', 'b', 'c', 'd', 'e'][i % 5],
  price: Math.round(Math.random() * 5e4) / 100, stock: i % 500,
  active: i % 3 !== 0,
}));
seed('customers', 5000, (i) => ({
  customerId: i, tier: ['free', 'pro', 'enterprise'][i % 3],
  city: RG[i % 4], spend: Math.round(Math.random() * 1e6) / 100,
}));
查看

几秒钟后,shell 打印:

控制台输出
orders: 120000
products: 20000
customers: 5000
原因

12 万条 orders 足以让一条没有索引的查询变得明显缓慢 — 而缓慢正是我们想要诊断的对象。

注意

如果之后查询没有超过 100 ms(机器较快),请回到这里把 120000 改成 300000

阶段 2

打开 Profiler 界面

步骤 2

首次打开

操作

通过以下 3 种方式中的任一方式打开 Profiler(它们都通向同一个地方 — 另外两种留到 Step 46 再测试):

  • 主菜单 → Database Profiler,或快捷键 Ctrl+Alt+Shift+P
  • 工具栏 → Monitoring → Database Profiler 菜单。
  • 在侧边栏的连接上右键Profiler
查看

一个名为 Profiler 的新标签打开,旁边显示连接名。从上到下,该标签包含:标题栏、控制条,以及四个分区按钮(DashboardLive FeedIndex AdvisorSessions)。

步骤 3

选择数据库

操作

在标题栏的 Database 字段中,选择 `profiler_lab`

查看

界面现在作用于该数据库。由于我们尚未打开 profiling,Dashboard 显示类似“No profiling data yet”的提示。

注意

profiler 是按数据库划分的。本手册中的所有操作都使用 profiler_lab。如果你选了另一个数据库,就看不到这些触发的结果。

阶段 3

打开 profiling

步骤 4

了解控制条

查看

标题栏正下方是一条控制条,包含:

  • Profiling — 三个按钮:Off · Slow ops · All ops
  • slowmsSample — 两个数字字段 + 一个 Apply 按钮。
  • Filter — 打开一个过滤器构建器。
  • ⏱ Capture — 安全的定时捕获。
  • system.profile — 该集合的小型使用条 + 一个 Resize 按钮。
  • Health — 带分数的等级(A–F)。

概念

三个级别。 Off = 不记录任何内容。Slow ops = 只记录超过 slowms 阈值的内容。All ops = 记录所有内容。为了测试,我们选用 All ops,以便看到全部流量。

步骤 5

在“All ops”级别打开

操作

点击 All ops 按钮。

  • 左侧的状态点变为蓝色
  • 出现一个警告药丸 “⚠ All ops”(提醒级别 2 会带来性能开销)。
  • 一条快速提示确认“Profiling level set to 2”。
原因

这是这个工具的核心。在旧版 profiler 中,这只是为你复制一段命令让你粘贴到 shell。现在点击会真正打开 profiling。如果状态点变蓝,主要的技术链路就工作正常了。✅

阶段 4

产生流量(“触发器”)

现在我们在 shell 中运行一些查询,让 Profiler 有东西可展示。保持 Profiler 标签打开 — 它每几秒会自动刷新。

步骤 6

触发器 A — 慢查询

操作

在 shell 中运行:

js·3 linhas
use profiler_lab;
db.orders.find({ status: 'shipped' }).toArray().length;
db.orders.find({ region: 'south' }).sort({ total: -1 }).toArray().length;
查看

1–3 秒内,在 Live Feed 分区中,出现两条针对 profiler_lab.orders 的新 query 操作行,带有红色的 COLLSCAN 徽标。

概念

COLLSCAN 与 IXSCAN。 COLLSCAN = MongoDB 逐个文档读取,因为没有索引 — 慢。IXSCAN = 使用了索引(一条捷径) — 快。红色徽标 = 不好;蓝色徽标 = 好。

步骤 7

触发器 B — 低效查询

操作

在 shell 中运行:

js·2 linhas
use profiler_lab;
db.orders.find({ status: 'refunded', region: 'north', items: 7 }).toArray();
查看

feed 中再多一行。Examined → Returned 列中的数字变成红色 — 为了返回区区几条它检查了 12 万条文档。

概念

低效。 当数据库“检查”的内容远多于“返回”的内容时,它在做无用功 — 这是一个建立索引的强力候选。

步骤 8

触发器 C — 写操作

操作

在 shell 中运行:

js·4 linhas
use profiler_lab;
db.orders.insertOne({ orderNo: 999001, status: 'paid', region: 'east', items: 2 });
db.orders.updateMany({ status: 'pending' }, { $set: { flagged: true } });
db.orders.deleteMany({ flagged: true, items: 3 });
查看

三条新操作:insertupdateremove

步骤 9

触发器 D、E、F — aggregation、count 和 cursors

操作

在 shell 中运行:

js·9 linhas
use profiler_lab;
db.orders.aggregate([
  { $match: { status: 'paid' } },
  { $group: { _id: '$region', n: { $sum: 1 }, rev: { $sum: '$total' } } },
]).toArray();
db.orders.countDocuments({ region: 'west' });
db.orders.distinct('status');
let cur = db.orders.find({}).batchSize(500).limit(5000);
let k = 0; while (cur.hasNext()) { cur.next(); k++; } print(k);
查看

command 类型的操作(aggregation、count)以及若干个 getmore(游标按批读取)。

步骤 10

触发器 G — 同一查询重复执行

操作

在 shell 中运行:

js·2 linhas
use profiler_lab;
for (let i = 0; i < 40; i++) db.orders.find({ status: 'paid' }).limit(10).toArray();
查看

feed 里此刻没什么特别的 — 但请记住:在 Step 24,这会在“Query shapes”面板中变成单独一行,计数为 40

阶段 5

探索 Live Feed

步骤 11

打开 feed

操作

点击 Live Feed 分区(在顶部)。

查看

一张包含操作的表格,最新的在最上面。列:时间、类型、集合、时长(按颜色编码 — 绿色快、红色慢)、plan(COLLSCAN/IXSCAN 徽标)、examined→returned,以及 app。顶部显示“X of Y operations”。

步骤 12

看实时模式工作

操作

再次运行 触发器 A(来自 Step 6),并留意 feed:

js·3 linhas
use profiler_lab;
db.orders.find({ status: 'shipped' }).toArray().length;
db.orders.find({ region: 'south' }).sort({ total: -1 }).toArray().length;
查看

几秒内,新行会自行出现在顶部。

步骤 13

暂停与恢复

操作

在标题栏点击 ● Live 按钮(它会变为 ⏸ Paused)。再次运行触发器 A:

js·3 linhas
use profiler_lab;
db.orders.find({ status: 'shipped' }).toArray().length;
db.orders.find({ region: 'south' }).sort({ total: -1 }).toArray().length;
查看

feed 不会增长 — 它被冻结了。点击 ⏸ Paused 回到 ● Live:它又开始增长。

原因

暂停在你想检查某一行而不希望列表跳动时很有用。

步骤 14

快速过滤(预设芯片)

操作

逐个点击 feed 顶部的芯片:

  • Slow > 100ms — 只显示慢操作。
  • COLLSCANs — 只显示没有索引的操作(红色徽标)。
  • Inefficient — 高亮 Step 7 中的那一条。
  • Writes — 只显示 insert/update/remove(来自 Step 8 的)。
  • Last 5 min — 只显示最近的流量。
查看

表格收缩为只显示匹配项。激活的芯片保持高亮。再次点击它即可关闭。

步骤 15

细粒度过滤

操作

按顺序执行:

  1. 1点击 type 芯片(queryinsertgetmore……)以开关它们。
  2. 2All collections 下拉中选择 orders
  3. 3search 框中输入 refunded
查看

每个过滤器都会缩小列表。它们相互组合生效。

步骤 16

全部清除

操作

点击 Clear filters(当存在活动过滤器时才会出现)。

查看

表格恢复显示全部内容。

阶段 6

探索 Dashboard

步骤 17

打开 Dashboard

操作

点击 Dashboard 分区。

查看

顶部四张数字卡片(OperationsSlow opsCollection scansAverage duration),下方是几张图表。

步骤 18

指标(KPI)

查看

四个数字反映你触发过的一切。“Collection scans”显示 COLLSCAN 的百分比 — 越高越糟。

步骤 19

时间线

查看

Operations over time 图按类型(reads、inserts、updates、deletes、commands)堆叠显示带状区域,并配有颜色编码的图例。

步骤 20

索引使用(环形图)

查看

Index usage 环形图把操作分为 COLLSCAN(红)、IXSCAN(蓝)和其他。此刻应该以红色为主导。

步骤 21

延迟分布

查看

按时间区间(0–1ms、……、>5s)分组操作的柱状图。

步骤 22

最热集合(treemap)

查看

方块大小与每个集合上花费的总时间成正比。orders 应该是最大的方块。

步骤 23

点击某个 treemap 方块

操作

点击 orders 方块。

查看

界面跳到 Live Feed,并已经按 orders 进行过滤。(之后回到 Dashboard。)

步骤 24

查询形态

查看

Query shapes 表把具有相同“形态”的查询分组到一起。你在 Step 10 重复 40 次的查询会以单独一行,计数为 40的形式出现,并把总时间汇总。

原因

这就是发现“哪条查询把所有执行加起来对数据库压力最大”的方式 — 即便每次单独执行都很快。

步骤 25

最慢的操作

查看

最后一张表列出 8 条最慢的操作。请记住它,下一步会用到。

阶段 7

钻取一条操作(drill-down)

步骤 26

打开详情面板

操作

点击任意一行 — 可以在 Live Feed、查询形态表,或最慢操作表中。

查看

右侧滑入一个面板,显示该操作的完整详情。

步骤 27

读懂这些数字

查看

一个网格,包含 Duration、Plan、Yields、Docs examinedKeys examinedReturned。如果该操作低效,会有一条红色警告说它是“strong index candidate”。

步骤 28

请求实时“explain”

操作

点击 Explain this query

查看

工具会即时运行 explain(),并显示真实的执行计划、执行时间和检查了多少文档 — 这有助于在当前数据库上确认诊断。

概念

Explain。 这是 MongoDB 在说明它打算如何运行这条查询。它能确认查询是否会使用索引。

步骤 29

查看命令与细节

操作

在面板中查看 Command 区域(该操作的 JSON),并点击复制图标。接着点击 Execution statsRaw document 来展开/折叠。

查看

命令被复制到剪贴板;两个区域可以打开或关闭。

步骤 30

关闭面板

操作

用面板顶部的 X 关闭它 — 然后再打开一个,通过点击面板旁的变暗区域来关闭。

查看

两种方式都能让面板消失。

阶段 8

使用 Index Advisor(亮点功能)

步骤 31

生成建议

操作

在 shell 中运行(3 条有问题的查询,重复 30 次):

js·6 linhas
use profiler_lab;
for (let i = 0; i < 30; i++) {
  db.orders.find({ status: 'shipped' }).toArray();
  db.orders.find({ region: 'north' }).sort({ createdAt: -1 }).limit(20).toArray();
  db.products.find({ category: 'c', active: true }).toArray();
}
查看

等待几秒。(下一步继续。)

步骤 32

打开 Index Advisor

操作

点击 Index Advisor 分区。

查看

顶部是一张带等级(A–F)的 Health 卡片 — 多半较低(C/D),因为你产生了大量 COLLSCAN。下方是 index recommendations 列表 — 大约 3 张卡片。

步骤 33

读懂一条建议

查看

每张卡片包含:严重性药丸(High/Medium/Low)、集合、查询“形态”、带有建议索引字段的芯片(附 ↑/↓ 箭头),以及一行影响信息(“N operations · X s total · M scans”)。

概念

为什么是这些字段、这个顺序。 advisor 遵循 ESR 规则:先 equality 字段,再 sort 字段,最后 range 字段。这是让索引最高效的顺序。

步骤 34

一键创建索引

操作

在某张卡片上点击 Create index。在弹窗中检查命令并确认。

查看

出现“Index created”提示。该建议的卡片变为 ✓ Already indexed

步骤 35

把其余的也建好

操作

对其他建议重复 Step 34。

查看

它们全都变为 ✓ Already indexed

阶段 9

确认确实变好

步骤 36

再次运行相同的查询

操作

再次运行 Step 31 中的同一段脚本(这里再贴一遍,你不用回翻):

js·6 linhas
use profiler_lab;
for (let i = 0; i < 30; i++) {
  db.orders.find({ status: 'shipped' }).toArray();
  db.orders.find({ region: 'north' }).sort({ createdAt: -1 }).limit(20).toArray();
  db.products.find({ category: 'c', active: true }).toArray();
}
查看

查询再次运行 — 这次你在阶段 8 创建的索引已经生效。

步骤 37

看 COLLSCAN 变成 IXSCAN

操作

切到 Live Feed

查看

相同的查询现在显示蓝色 IXSCAN 徽标,时长短得多。它们之前读取了 12 万条文档;现在使用了索引。

步骤 38

看 Health 等级上升

操作

回到 Index Advisor(或点击控制条中的 Health 药丸)。

查看

等级上升了(例如从 C/D 到 A/B),建议数量减少。你刚刚完成了一个完整的循环:诊断 → 修复 → 验证。✅

阶段 10

Sessions 与报告

概念

Session。 当前 profiling 状态的一个“快照”,以一个名字保存。它用于比较某次变更的“之前”和“之后”。

步骤 39

保存一个会话

操作

进入 Sessions,输入一个名字(例如 after the indexes),点击 Save session

查看

该会话出现在列表中,带有它的指标和日期。

步骤 40

对比

操作

在列表中勾选两个条目 — 例如保存的会话与 Current window(它始终在最上方)。

查看

出现一张 Comparison 表,带有按颜色编码的 Δ 列 — 变好时为绿色(COLLSCAN 更少、用时更短),变差时为红色。

步骤 41

导出报告

操作

点击 Export report

查看

下载一个 .json 文件,包含 health、建议、查询形态以及最慢的操作 — 可以附到工单里或归档备查。

阶段 11

控制与安全功能

步骤 42

安全的定时捕获

概念

为什么有这个。 把级别 2 一直开着并忘掉它在生产中很危险。“capture”会打开级别 2、运行一段倒计时,在结束时自动关闭

操作

在控制条点击 ⏱ Capture 并选择 30s。在这 30 秒内,运行任意触发器 — 例如触发器 A:

js·3 linhas
use profiler_lab;
db.orders.find({ status: 'shipped' }).toArray().length;
db.orders.find({ region: 'south' }).sort({ total: -1 }).toArray().length;
查看

profiling 切换到级别 2,出现一个带倒计时的药丸。倒计时归零时,级别自动恢复到之前的状态,并提示“Capture complete”。(你也可以点击 Cancel 提前结束。)

步骤 43

Profiling 过滤器

操作

点击 Filter,把 Namespace 填为 orders,点击 Apply filter。然后运行触发器 A:

js·3 linhas
use profiler_lab;
db.orders.find({ status: 'shipped' }).toArray().length;
db.orders.find({ region: 'south' }).sort({ total: -1 }).toArray().length;
操作

之后点击 Filter → Clear filter

查看

在过滤器生效时,只有 orders 上的操作会被记录(按钮显示“Filter active”)。清除后,恢复为记录全部内容。

步骤 44

管理 system.profile 集合

概念

Capped collection。 profiler 的日志大小固定;装满时会删除最旧的条目。默认(1 MB)会很快被填满。

操作

观察控制条上的 system.profile 条(显示 used / total)。点击 Resize,选择 10 MB,确认。

查看

条目现在显示 ~/10 MB。弹窗提醒你重新调整大小会清掉当前历史。

步骤 45

调整 slowms 和采样率

操作

slowms 改成 50,点击 Apply。然后点击 Slow ops 并运行触发器 A:

js·3 linhas
use profiler_lab;
db.orders.find({ status: 'shipped' }).toArray().length;
db.orders.find({ region: 'south' }).sort({ total: -1 }).toArray().length;
查看

在“Slow ops”级别下,只有慢于设定的 slowms 的操作才会进入 feed — 快操作会被忽略。

阶段 12

收尾

步骤 46

其他打开方式

操作

测试 Step 2 中你还没使用过的另外两个入口。

查看

它们都会打开 Profiler 标签。如果某个标签已经打开,就会聚焦到已有的那个,而不是再开一个。

步骤 47

语言

操作

Settings → Language 中切换语言(共 5 种)。回到 Profiler。

查看

整个 Profiler 界面都呈现已翻译的状态 — 不会出现 profiler.xyz 这种“原始”字符串。

步骤 48

主题

操作

LightDarkNeon 之间切换主题。

查看

颜色、卡片和图表都会自适应;没有看不见的文字。

清理(完成后)

操作

在 shell 中运行:

js·3 linhas
use profiler_lab;
db.setProfilingLevel(0);
db.dropDatabase();
查看

Profiling 被关闭,实验数据库被清除。

你已验证内容的总结

阶段功能
2–3打开 Profiler(3 种入口)+ 选择数据库
3真正打开 profiling(Off / Slow / All)
4–5Live Feed:实时、暂停、预设、过滤、搜索
6Dashboard:KPI、时间线、环形图、延迟、treemap、查询形态
7Drill-down:详情、实时 explain()、命令、raw
8–9Index Advisor:建议、创建索引、验证改进
10Sessions:保存、对比、导出报告
11定时捕获、过滤、调整大小、slowms
12其他入口、5 种语言、3 种主题
如果每个步骤都给出了预期的“查看”结果,那么 Profiler 界面已 100% 验证通过。请把任何不一致的步骤编号记下来,以便我们修复。