运行 一个循环所用的时间(Progress 4GL)

Time taken to run a loop (Progress 4GL)

我写了一个查询,其中包含多个 for each 语句。查询需要 20 多分钟来获取数据。有没有办法检查每个循环开始和结束的时间。 (每个循环执行需要多少时间以及完成程序所需的总时间)。

使用ETIME您可以启动毫秒计数器。它可以被调用一次或多次以告知自重置以来已经过去了多长时间。

ETIME(TRUE).

/*
Loop is here but instead I'll insert a small pause.
*/
PAUSE 0.5.

MESSAGE "This took" ETIME "milliseconds" VIEW-AS ALERT-BOX.

处理几分钟时,毫秒可能没​​有用。然后你可以使用 TIME 来跟踪秒数,但你需要自己处理开始时间。

DEFINE VARIABLE iStart AS INTEGER NO-UNDO.

iStart = TIME.

/*
Loop is here but instead I'll insert a slightly longer pause.
*/
PAUSE 2.

MESSAGE "This took" TIME - iStart "seconds" VIEW-AS ALERT-BOX.

如果您想跟踪多次,那么输出到日志文件可能更好,而不是使用 MESSAGE-box,它将停止执行直到被点击。

DEFINE VARIABLE i AS INTEGER NO-UNDO.
DEFINE STREAM str.    
OUTPUT STREAM str TO c:\temp\timing.txt.

ETIME(TRUE).
/*
Fake loop
*/
DO i = 1 TO 20:
    PAUSE 0.1.
    PUT STREAM str UNFORMATTED "Timing no " i " " ETIME "ms" SKIP.
END.
OUTPUT CLOSE.

您可以按照您的要求进行操作(只需遵循 JensD 的建议),但使用分析器可能会更好。您可以轻松地为代码片段添加分析:

assign
  profiler:enabled     = yes
  profiler:description = "description of this test"
  profiler:profiling   = yes
  profiler:file-name   = "filename.prf"
. 

/* this is deliberately awful code that should take a long time to run */

for each orderline no-lock:

  for each order no-lock:

    for each customer no-lock:

      if customer.custNum = order.custNum and orderLine.orderNum = orderLine.orderNum then
        . /* do something */

    end.

  end.

end.

/* end of test snippet */

assign
  profiler:enabled     = no
  profiler:profiling   = no
.

profiler:write-data().

然后您可以将该 prf 文件加载到分析工具中。具体细节取决于您的开发环境——如果您使用的是最新版本的 PSDOE,则包含一个 Profiler 分析器,如果没有,您可能需要下载 ProTop https://demo.wss.com/download.php 并使用 lib/zprof_topx.p.

中包含的简单报告

最终您会发现,您的一个或多个 FOR EACH 语句几乎肯定使用了与可用索引不匹配的 WHERE 子句。

要解决此问题,您需要确定实际选择了哪些索引并查看索引选择规则。可以在此处找到关于该主题的一些优秀 material:http://pugchallenge.org/downloads2019/303_FindingData.pdf

如果您不想费心阅读那篇文章,那么您至少应该看一下实际的索引选择,如下所示:

compile program.p xref program.xref

所选指数是否符合您的预期? WHOLE-INDEX(又名 "table scan")出现了吗?