如何在PostgreSQL中跟踪查询进度?

Moh*_*jar 14 postgresql

是否有一个插件或脚本可以跟踪PostgreSQL中长查询的进度?

我的意思是我需要在Java中设置与Postgres中的某些更新查询相关的进度条值.我通过互联网搜索,但我刚发现一些文件在任何RDBMS系统中都没有任何官方实现.

jjr*_*jrv 22

我在这里找到了一个很好的答案:跟踪更新声明的进度

诀窍是首先创建一个序列(根据需要命名):

CREATE SEQUENCE query_progress START 1;
Run Code Online (Sandbox Code Playgroud)

然后附加到查询的WHERE部分:

AND NEXTVAL('query_progress')!=0
Run Code Online (Sandbox Code Playgroud)

现在您可以查询进度:

SELECT NEXTVAL('query_progress');
Run Code Online (Sandbox Code Playgroud)

最后不要忘记摆脱序列:

DROP SEQUENCE query_progress;
Run Code Online (Sandbox Code Playgroud)

请注意,这很可能会使您的查询运行速度更慢,每次检查进度时它都会增加值.上面的链接建议创建一个临时序列,但PostgreSQL似乎不会使它们在会话中可见.

  • 这是一个有趣的解决方案,但我认为要查询进度,最好调用 `currval` 函数:`SELECT CURRVAL('query_progress');` PS:可以在更新查询后调用 `currval` 函数已完成,否则您将收到一条错误消息:“错误:序列“query_progress”的 currval 尚未在此会话中定义”;在这种情况下,您可以使用此查询:`SELECT last_value FROM query_progress;`,即使您的更新查询没有启动,它也应该返回一个值。 (4认同)
  • 这很酷而且很有创意。这也确实很 hacky,但是哦,好吧……希望 Postgres 有一天能为我们提供一个真正的解决方案。 (2认同)

Yun*_*hao 7

我想出了一个可能有帮助的方法。但是,如果您想将其实现到您的代码(如 Java 等)中,则可能需要进一步处理。

方法是检查页面内容以跟踪进度。

Postgresql 有一个名为 pageinspect 的扩展,可以检查特定表的页面信息。

此处的详细信息:https : //www.postgresql.org/docs/current/pageinspect.html

也花一些时间在这里了解 postgresql 的页面布局

https://www.postgresql.org/docs/current/storage-page-layout.html

特别查看 xmin、xmax 和 ctid

我假设表中的行插入遵循特定顺序。就像桌子的钥匙一样。任何长时间的更新都可能会附加新页面。

我还假设主键 id 大部分是连续的,几乎没有间隙。既然只是估计,我觉得这个条件还可以。

但是,您无法通过这样做找出总页码SELECT relname, relpages FROM pg_class,因为它没有更新。

如果页面索引在 strage 中不存在,您将遇到异常(但您会找到该页面,即使它没有在 pg_class 左右更新),因此在“page_index”上进行一点“二进制搜索”以找到您拥有的最大页面。不需要很准确。

SELECT backend_xid FROM pg_stat_activity WHERE pid = process-id
Run Code Online (Sandbox Code Playgroud)

查找您当前的交易 ID。

SELECT lp,t_xmin,t_xmax,t_ctid,t_bits,t_data FROM heap_page_items(get_raw_page('relation_name', page_index));
Run Code Online (Sandbox Code Playgroud)

在我正在处理的示例中,它可能看起来像这样

SELECT lp,t_xmin,t_xmax,t_ctid,t_bits,t_data FROM heap_page_items(get_raw_page('foo', 3407000));

LP | t_xmin | t_xmax | t_ctid | t_bits | t_data

1 | 592744 | 592744 | (3407000,1) | 110000000111000000000000 | \xd1100000000000000e4400000000000054010000611b0000631b0000

2 | 592744 | 592744 | (3407000,2) | 110000000111000000000000 | \xd110000000000000104400000000000040010000611b0000631b0000

3 | 592744 | 592744 | (3407000,3) | 110000000111000000000000 | \xd11000000000000011440000000000007c010000611b0000631b0000

t_data 是数据。lp 是项目列表中的元组索引。t_xmin 和 t_xmax 是事务 ID。并且 t_ctid 是元组本身中元组的点。如果元组中有空值,则 t_bits 是 NULL 位图。

首先查看t_min = t_max,和t_ctid(page_index, tuple_id)和lp是否相同。如果是,请检查 t_xmin 是否与您的交易 ID 相同。如果是这样检查数据。

注意字节序和空位图。就我而言,它是大端(LSB 优先)。

在我的示例中,第一行是有效的。第一个 BIGINT(8 个字节 16 个十六进制数)是我正在查找的排序 ID。所以第一行的数据是

\xd110000000000000

转换为 0x101d(检查字节序)--> 4305

我知道我最大的 id 是 18209,smallest_id 是 2857。我把工作分成 8 部分,所以

(18209 - 2857) / 8 = 1919

这是我运行的第一部分。所以

2857 + 1919 = 4776

这意味着我的子作业从 2857 id 开始,目前在 4305。如果它达到 4776,这个线程就完成了!

这是

(4305 - 2857)/ 1919 = 75.5% 完成


限制

这不适用于哈希值更新。在我的情况下,id 恰好作为 pkey 顺序排序。规划器触发顺序读取。如果规划器正在执行某种 btree 索引扫描以进行更新,这也应该有效。

如果您有兴趣按索引顺序对物理行进行排序,请查看CLUSTER

同样,这种方法并不准确。并根据上面强调的假设。如果在程序中使用,应该使用 sparsely 以防止磁盘 I/O 的额外开销


Ric*_*ton 0

不可以。没有办法跟踪查询的“实时”进度。理论上,系统可以将顶级进度与查询计划进行比较,并发出某种百分比读数。在实践中,我怀疑它是否非常准确,并且我怀疑对性能的影响是否值得。