【问题标题】:Profiling Mnesia Queries分析 Mnesia 查询
【发布时间】:2010-12-23 10:33:02
【问题描述】:

我们的 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 优化的“原因”。

【问题讨论】:

    标签: database erlang profiling mnesia


    【解决方案1】:

    由于 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}]}.
    

    【讨论】:

    • 正如 Gordon 已经建议的那样,这些工具只会产生类似“你在 mnesia:match_object 和 qlc:eval 上花费了太多时间”之类的东西。虽然我想一个真正的答案是“你在这里和那里加入一个非索引列,让你的记忆变慢”。
    • 并非如此。 qlc:eval 和 mnesia:match_object 调用其他 erlang 函数。我相信您可以获得更多信息,而不仅仅是您将大部分时间花在 mnesia:match_object 上。不过,我会看看我是否可以尝试一下。
    • 那么这个 fprof 跟踪是否为您提供了有关如何更改架构的任何提示?
    • Zed 是对的。我现在正在研究我的 fprof 输出:( 当我应该有一个 mnesia:index_match_object/4 但它不是查询分析器时,我确实“解决”了我使用的是 mnesia:match_object3 :(
    【解决方案2】:

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

    这些工具fprof 等听起来像是从gprof 获得基本方法的大多数工具,即检测函数、计数调用、对程序计数器进行采样等。很少有人长期使用examined the foundations 这种做法时间。对于此类工具的用户来说,您的挫败感听起来很典型。

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

    Here's a case study of the use of the method.

    【讨论】:

    • 非常有趣的评论。虽然不完全确定如何在 Erlang 中做到这一点......但它确实提出了许多做事的方法......我们有一组相当复杂的数据访问例程来做一些(奇怪的)事情,我们知道我们有一个大数据访问层要重写——所以我会牢记这种技术。谢谢
    • @Gordon:我正在寻找一个带有暂停或 ctrl-break 按钮的调试器。有像pstack 这样的工具可以让你从外部获取堆栈截图。有一些分析工具可以对调用堆栈进行采样,但它们不一定以有用的方式进行,即按挂钟时间采样,并让您分析单个代表性样本。
    • ... 基本思想是,如果花费了一段时间,那么调用堆栈的状态(可能还有其他数据)会尽可能多地告诉您为什么要花费这些时间,包括请求它的函数调用的层次结构。
    【解决方案3】:

    Mike Dunlavey 的建议让我想起了 redbug,它允许您在生产系统中对调用进行采样。将其视为易于使用的erlang:trace,它不会为您提供足够的绳索来悬挂您的生产系统。

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

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

    但无法获取这些跟踪的通话持续时间。

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

    【讨论】:

    • @Christian:这很有帮助。我的理论是你不需要知道通话时间。相反,您需要知道每个调用处于活动状态的时间百分比(假设样本是在“随机”时间获取的,它在堆栈样本中的百分比),因为这告诉您该调用负责的总时间的比例是多少,您如果您可以将其删除,则可以保存。
    猜你喜欢
    • 2012-06-08
    • 1970-01-01
    • 2011-01-26
    • 2017-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-10
    • 2011-03-02
    相关资源
    最近更新 更多