【问题标题】:How to log queries inside PLPGSQL with inlined parameter values如何使用内联参数值在 PLPGSQL 中记录查询
【发布时间】:2017-01-29 01:16:16
【问题描述】:

当我的PLPGSQL 函数(Postgres 9.6)中的语句正在运行时,我可以在一行上看到查询,然后在另一行上看到所有参数。 2 行日志记录。比如:

LOG:  execute <unnamed>: SELECT * FROM table WHERE field1=$1 AND field2=$2 ...    
DETAIL:  parameters: $1 = '-767197682', $2 = '234324' ....

是否可以将整个查询记录在 pg_log WITH 查询中已替换的参数并将其记录在 SINGLE 行中?

因为这样可以更轻松地复制/粘贴查询以在另一个终端中重现它,尤其是在查询有几十个参数的情况下。

【问题讨论】:

  • 我认为您无法更改日志记录格式。与其尝试自己替换参数,不如通过PREPARE/EXECUTE 运行查询更容易。您应该能够使用一些相当简单的正则表达式将这些日志行转换为可运行的脚本。
  • @NickBarnes,谢谢。似乎脚本将是唯一的解决方案。
  • 如有必要,您可以在代码中添加RAISE NOTICE(或类似名称),并记录任何必要的内容。

标签: postgresql logging prepared-statement plpgsql sql-execution-plan


【解决方案1】:

这背后的原因:PL/pgSQL 内部将 SQL 语句视为准备好的语句

首先:在默认设置下,PL/pgSQL 函数中根本没有没有记录 SQL 语句。你在用auto_explain吗?

在同一会话中的前几次调用中,SPI 管理器(服务器编程接口)根据 实际 参数值生成新的执行计划。任何类型的日志记录都应该报告参数值内联

Postgres 会跟踪并在当前会话中的几次调用之后,如果执行计划似乎对实际参数值不敏感,它将开始重用一个通用的缓存计划。然后您应该看到带有$n 参数的准备好的语句的通用计划(如问题中所示)。

chapter "Plan Caching" in the manual中的详细信息。

您可以通过一个简单的演示来观察效果。在同一个会话中(不一定是同一个事务):

CREATE TEMP TABLE tbl AS
SELECT id FROM generate_series(1, 100) id;

PREPARE prep1(int) AS
SELECT min(id) FROM tbl WHERE id > $1;

EXPLAIN EXECUTE prep1(3);  -- 1st execution

你会看到实际值:

  Filter: (id > 3)
EXECUTE prep1(1);  -- several more executions
EXECUTE prep1(2);
EXECUTE prep1(3);
EXECUTE prep1(4);
EXECUTE prep1(5);

EXPLAIN EXECUTE prep1(3);

现在你会看到一个$n 参数:

  Filter: (id > $1)

因此,您可以在当前会话的前几次调用中获得带有参数值的查询内联

或者您可以将动态 SQL 与 EXECUTE 一起使用,因为 per documentation:

此外,对于通过EXECUTE 执行的命令,没有计划缓存。 相反,每次运行语句时总是计划命令。 因此,可以在函数内动态创建命令字符串 对不同的表和列执行操作。

当然,这实际上会影响性能。

相关:

【讨论】:

    猜你喜欢
    • 2019-06-08
    • 1970-01-01
    • 2020-02-27
    • 2017-10-23
    • 2023-03-12
    • 2021-05-05
    • 2016-03-05
    • 1970-01-01
    • 2017-04-30
    相关资源
    最近更新 更多