13

我们的 Mnesia DB 运行缓慢,我们认为它应该更快一些。

因此,我们需要对其进行分析并找出正在发生的事情。

有许多选项可以自我暗示:

  • 运行 fprof 并查看时间在哪里
  • 运行 cprof 看看哪些函数被调用了很多

然而,这些都是相当标准的性能监控风格工具。问题是我如何实际进行查询分析 - 哪些查询花费的时间最长。如果我们是 Oracle 或 MySQL 商店,我们只需运行一个查询分析器,它会返回需要很长时间才能运行的各种查询。这似乎不是 Mnesia 可用的工具。

所以问题是:

  • 有哪些技术可以描述 Mnesia
  • 有哪些工具可以用来描述 Mnesia - 我认为没有,但证明我错了 :)
  • 你是如何分析你的查询和优化你的 mnesia 数据库安装的

根据讨论展开

fprof 作为分析工具的问题之一是它只告诉您正在查看的特定查询。所以 fprof 告诉我 X 很慢,我将其调低以加快速度。然后,低,看,操作 Y(足够快)现在变得很慢。所以我分析了 Y 并意识到让 Y 快的方法就是让 X 慢。所以我最终做了一系列双边权衡......

我真正需要的是一种管理多边权衡的方法。我现在记录了 2 个度量标准的实际用户活动负载,我可以重播这些活动。这些日志代表我想要优化的内容。

SQL 数据库上的“适当”查询分析器将能够分析 SQL 语句的结构,例如所有具有以下形式的语句:

SELECT [fieldset] FROM [table] WHERE {field = *parameter*}, {field = *parameter*}

并且说这种形式的 285 个查询平均需要 0.37 毫秒才能运行

他们神奇的答案是当它说:这种形式的 17 个查询运行了 6.34 秒并对表 X 进行了全表扫描,你应该在字段 Y 上放置一个索引

当我在一组具有代表性的用户活动上得到这样的结果集时,我就可以开始全面考虑权衡取舍 - 并设计一个测试模式。

测试模式将类似于:

  • 活动 X 将使查询 A、C 和 C 更快,但查询 E 和 F 更慢
  • 测试和测量
  • 然后批准/不批准

我已经使用 Erlang 足够长的时间来“知道”没有像这样的查询分析器,我想知道其他人(他们一定有这个问题)是如何对 mnesia 优化的“原因”。

4

3 回答 3

3

我犹豫了,因为我对 Erlang 或 Mnesia 都不太了解,但我对性能调优了解很多,从目前的讨论来看,这听起来很典型。

这些工具fprof等听起来像大多数工具,它们的基本方法都来自gprof,即检测函数、计数调用、对程序计数器进行采样等。很长一段时间以来,很少有人研究过这种实践的基础。对于此类工具的用户来说,您的挫败感听起来很典型。

您可能会考虑一种鲜为人知的方法,此处概述。它基于随机抽取程序状态的少量(10-20)样本,并理解每个样本,而不是总结。通常,这意味着检查调用堆栈,但您可能还想检查其他信息。有不同的方法可以做到这一点,但我只是在调试器中使用暂停按钮。我不是想获得精确的时间或调用计数。这些充其量只是间接线索。相反,我询问每个样本“它在做什么以及为什么?”如果我发现它正在执行某些特定活动,例如执行 X 查询,它正在为目的 z 寻找 y 类型的答案,并且它在多个样本上执行它,那么它正在执行的样本的分数是粗略但可靠地估计它执行此操作的时间比例。很有可能这是我可以做的事情,并获得很好的加速。

这是该方法使用的案例研究。

于 2009-12-08T03:18:57.817 回答
2

Mike Dunlavey 的建议让我想起了redbug,它允许您在生产系统中对调用进行采样。把它想象成一个易于使用的erlang:trace工具,它不会给你足够的绳索来悬挂你的生产系统。

使用类似这样的调用应该会给你很多堆栈跟踪来识别你的 mnesia 事务是从哪里调用的:

redbug:start(10000,100,{mnesia,transaction,[stack]}).

但是,不可能获得这些跟踪的通话持续时间。

如果您已将所有 mnesia 查找组织到导出 api 以执行它们的模块中,您还可以使用 redbug 仅获取特定查询的调用频率。

于 2009-12-13T20:45:22.863 回答
2

由于 Mnesia 查询只是 erlang 函数,我想您可以像分析自己的 erlang 代码一样分析它们。http://www.erlang.org/doc/efficiency_guide/profiling.html#id2266192有更多关于可用的 erlang 分析工具的信息。

更新作为一个测试,我在家里的一个测试 mnesia 实例上运行了这个,并使用 fprof 来跟踪一个 mnesia qlc 查询返回的输出一个我在下面包含的示例。所以它肯定包含比查询调用更多的信息。

....
{[{{erl_lint,pack_errors,1},                      2,    0.004,    0.004}],     
 { {lists,map,2},                                 2,    0.004,    0.004},     %
 [ ]}.

{[{{mnesia_tm,arrange,3},                         1,    0.004,    0.004}],     
 { {ets,first,1},                                 1,    0.004,    0.004},     %
 [ ]}.

{[{{erl_lint,check_remote_function,5},            2,    0.004,    0.004}],     
 { {erl_lint,check_qlc_hrl,5},                    2,    0.004,    0.004},     %
 [ ]}.

{[{{mnesia_tm,multi_commit,4},                    1,    0.003,    0.003}],     
 { {mnesia_locker,release_tid,1},                 1,    0.003,    0.003},     %
 [ ]}.

{[{{mnesia,add_written_match,4},                  1,    0.003,    0.003}],     
 { {mnesia,add_match,3},                          1,    0.003,    0.003},     %
 [ ]}.

{[{{mnesia_tm,execute_transaction,5},             1,    0.003,    0.003}],     
 { {erlang,erase,1},                              1,    0.003,    0.003},     %
 [ ]}.

{[{{mnesia_tm,intercept_friends,2},               1,    0.002,    0.002}],     
 { {mnesia_tm,intercept_best_friend,2},           1,    0.002,    0.002},     %
 [ ]}.

{[{{mnesia_tm,execute_transaction,5},             1,    0.002,    0.002}],     
 { {mnesia_tm,flush_downs,0},                     1,    0.002,    0.002},     %
 [ ]}.

{[{{mnesia_locker,rlock_get_reply,4},             1,    0.002,    0.002}],     
 { {mnesia_locker,opt_lookup_in_client,3},        1,    0.002,    0.002},     %
 [ ]}.

{[ ],
 { undefined,                                     0,    0.000,    0.000},     %
 [{{shell,eval_exprs,6},                          0,   18.531,    0.000},      
  {{shell,exprs,6},                               0,    0.102,    0.024},      
  {{fprof,just_call,2},                           0,    0.034,    0.027}]}.
于 2009-12-04T23:11:36.067 回答