PostgreSQL日志中的SQL记录时机 —— log_statement 和 log_min_duration_statement
最近跟朋友讨论到PostgreSQL日志中的SQL记录时机,研究了下log_statement 和 log_min_duration_statement两个参数,记录一下。
一、 参数简介
1. log_statement
① 作用
控制记录SQL的类型,可选值为:
- none:关闭(默认)
- ddl:DDL语句
- mod:DDL和所有涉及数据修改的语句(DML、COPY FROM、PREPARE、EXECUTE等)。对于explain和explain analyze,如果后面的语句类型符合,也会被记录
- all:所有语句
② 记录时机
SQL语句解析成功后,执行前。因此即使设置为all,也不会记录有语法错误的语句(如果想记录,应该使用log_min_error_statement参数)。
③ 记录内容
记录SQL语句,包含参数,但不包含执行用户、主机名等信息,这些需要审计插件才有。
2. log_min_duration_statement
① 作用
记录超过指定执行时间阈值的SQL,可选值为:
- -1:关闭(默认)
- 0:所有语句
- 正数:慢SQL阈值
② 记录时机
SQL语句执行完成后,因此能记录到执行时间。
③ 记录内容
- 记录SQL语句、执行时间,但不包含参数。
- 对于使用扩展查询协议的客户端,对语法分析、绑定、执行每一步所花时间会独立记录。
3. 同时符合两者的SQL会如何?
- 语句在解析完成后、执行开始前,即被记入日志(log_statement生效)
- 语句执行完成后,单独将duration记入日志(log_min_duration_statement生效),但不再重复记录语句
- 因此建议使用log_line_prefix记录PID或会话ID,避免duration和语句关联不上
二、 效果测试
1. 两者均设置
log_statement='all',log_min_duration_statement='0s'
2023-11-28 17:51:45.222 CST [2484] LOG: statement: select pg_sleep(10);
2023-11-28 17:51:55.227 CST [2484] LOG: duration: 10005.249 ms
语句记录为开始时间(log_statement生效),duration在执行完成时单独记录(log_min_duration_statement生效),但不再重复记录语句。
2. 仅设置log_statement
log_statement='all',log_min_duration_statement='-1'(禁用)
2023-11-28 17:53:49.540 CST [2760] LOG: statement: select pg_sleep(10);
仅记录语句,记录时间为开始时间,没有duration
3. 仅设置log_min_duration_statement
log_statement='none'(禁用),log_min_duration_statement='0s'
2023-11-28 17:55:20.288 CST [2826] LOG: duration: 15015.447 ms statement: select pg_sleep(15);
记录语句和duration,记录时间为结束时间
三、 参数记录时机
从上面文档可以知道,两个参数记录时机都在SQL执行阶段,只是一个在前一个在后。源码中SQL执行相关的函数主要是exec_simple_query,因此我们就看看这个函数。
函数刚开头就可以看到 pg_parse_query 和 check_log_statement函数。
/** exec_simple_query** Execute a "simple Query" protocol message.*/
static void
exec_simple_query(const char *query_string)
{CommandDest dest = whereToSendOutput;MemoryContext oldcontext;List *parsetree_list;ListCell *parsetree_item;bool save_log_statement_stats = log_statement_stats;bool was_logged = false;bool use_implicit_block;char msec_str[32];
.../** Do basic parsing of the query or queries (this should be safe even if* we are in aborted transaction state!)*/parsetree_list = pg_parse_query(query_string);/* Log immediately if dictated by log_statement */if (check_log_statement(parsetree_list)){ereport(LOG,(errmsg("statement: %s", query_string),errhidestmt(true),errdetail_execute(parsetree_list)));was_logged = true;}
- pg_parse_query函数用于SQL解析,符合log_statement记录的语句发生在解析完成后
- check_log_statement函数就用于检查log_statement的设置,标记是否需要记录
- was_logged=true表示已记录SQL语句,主要是给后面的慢SQL记录函数,提示其不需重复记录SQL文本
/** check_log_statement* Determine whether command should be logged because of log_statement** stmt_list can be either raw grammar output or a list of planned* statements*/
static bool
check_log_statement(List *stmt_list)
{ListCell *stmt_item;if (log_statement == LOGSTMT_NONE)return false;if (log_statement == LOGSTMT_ALL)return true;/* Else we have to inspect the statement(s) to see whether to log */foreach(stmt_item, stmt_list){Node *stmt = (Node *) lfirst(stmt_item);if (GetCommandLogLevel(stmt) <= log_statement)return true;}return false;
}
后面一大堆是SQL执行相关的代码,非本次重点,直接拉到函数末尾,可以看到check_log_duration函数,看名字都能猜到是它了,也符合在SQL执行完才记录。
.../** Emit duration logging if appropriate.*/switch (check_log_duration(msec_str, was_logged)){case 1:ereport(LOG,(errmsg("duration: %s ms", msec_str),errhidestmt(true)));break;case 2:ereport(LOG,(errmsg("duration: %s ms statement: %s",msec_str, query_string),errhidestmt(true),errdetail_execute(parsetree_list)));break;}if (save_log_statement_stats)ShowUsage("QUERY STATISTICS");TRACE_POSTGRESQL_QUERY_DONE(query_string);debug_query_string = NULL;
}
check_log_duration函数
可以看到注释中给出了上面case 1,2的含义:
- 1:仅记录duration,即前面提到的两个参数均生效的场景
- 2:记录duration和语句:即前面提到的仅log_min_duration_statement生效的场景
另外是否记录慢sql与 log_duration、log_min_duration_sample 这些参数也有关。
/** check_log_duration* Determine whether current command's duration should be logged* We also check if this statement in this transaction must be logged* (regardless of its duration).** Returns:* 0 if no logging is needed* 1 if just the duration should be logged* 2 if duration and query details should be logged** If logging is needed, the duration in msec is formatted into msec_str[],* which must be a 32-byte buffer.** was_logged should be true if caller already logged query details (this* essentially prevents 2 from being returned).*/
int
check_log_duration(char *msec_str, bool was_logged)
{if (log_duration || log_min_duration_sample >= 0 ||log_min_duration_statement >= 0 || xact_is_sampled){long secs;int usecs;int msecs;bool exceeded_duration;bool exceeded_sample_duration;bool in_sample = false;TimestampDifference(GetCurrentStatementStartTimestamp(),GetCurrentTimestamp(),&secs, &usecs);msecs = usecs / 1000;/** This odd-looking test for log_min_duration_* being exceeded is* designed to avoid integer overflow with very long durations: don't* compute secs * 1000 until we've verified it will fit in int.*/exceeded_duration = (log_min_duration_statement == 0 ||(log_min_duration_statement > 0 &&(secs > log_min_duration_statement / 1000 ||secs * 1000 + msecs >= log_min_duration_statement)));exceeded_sample_duration = (log_min_duration_sample == 0 ||(log_min_duration_sample > 0 &&(secs > log_min_duration_sample / 1000 ||secs * 1000 + msecs >= log_min_duration_sample)));/** Do not log if log_statement_sample_rate = 0. Log a sample if* log_statement_sample_rate <= 1 and avoid unnecessary random() call* if log_statement_sample_rate = 1.*/if (exceeded_sample_duration)in_sample = log_statement_sample_rate != 0 &&(log_statement_sample_rate == 1 ||random() <= log_statement_sample_rate * MAX_RANDOM_VALUE);if (exceeded_duration || in_sample || log_duration || xact_is_sampled){snprintf(msec_str, 32, "%ld.%03d",secs * 1000 + msecs, usecs % 1000);if ((exceeded_duration || in_sample || xact_is_sampled) && !was_logged)return 2;elsereturn 1;}}return 0;
}
参考:
https://www.postgresql.org/docs/current/runtime-config-logging.html#GUC-LOG-STATEMENT
https://www.postgresql.org/docs/current/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY
https://blog.csdn.net/qq_35423190/article/details/129138740
https://iwmj.wordpress.com/2018/04/03/postgresql-%E5%89%8D%E5%90%8E%E7%AB%AF%E5%8D%8F%E8%AE%AE%E4%B8%AD%E7%9A%84%E6%9F%A5%E8%AF%A2%E6%96%B9%E5%BC%8F%EF%BC%9A%E7%AE%80%E5%8D%95%E6%9F%A5%E8%AF%A2%E3%80%81%E6%89%A9%E5%B1%95%E6%9F%A5%E8%AF%A2/
相关文章:
PostgreSQL日志中的SQL记录时机 —— log_statement 和 log_min_duration_statement
最近跟朋友讨论到PostgreSQL日志中的SQL记录时机,研究了下log_statement 和 log_min_duration_statement两个参数,记录一下。 一、 参数简介 1. log_statement ① 作用 控制记录SQL的类型,可选值为: none:关闭&…...

Agent举例与应用
什么是Agent OpenAI 应用研究主管 Lilian Weng 在一篇长文中提出了 Agent LLM(大型语言模型)记忆规划技能工具使用这一概念,并详细解释了Agent的每个模块的功能。她对Agent未来的应用前景充满信心,但也表明到挑战无处不在。 现…...

CentOS 7 配置tomcat
简介 Tomcat是一个使用Java编写的开源Web应用服务器,是由Apache Software Foundation管理的一个项目。它是一个轻量级的应用服务器,可以下载、安装和使用,而且还提供了许多高级功能,例如支持Java Servlet、JavaServer Pages (JSP)和JavaServer Faces (JSF) 等JavaEE技术,…...
如何优雅的关闭一个IIS站点
众所周知,当我们使用IIS的时候,在使用负载均衡的情况下,想停掉一个站点,通常会点击Sites(网站)中的Stop(停止)来停止一个站点。但是这样做,会带来一个问题,当…...

弱网模拟工具
一、背景 一个人晚上在家通过 Wi-Fi 上网,在线电影播放基本流畅,可一旦在晚间用网高峰期打视频电话就画面糊,这时不仅可能带宽受限了,还可能有较高的丢包率。与有线网络通信相比,无线网络通信受环境影响会更大&#x…...
Leetcode 第 110 场双周赛 Problem D 2809. 使数组和小于等于 x 的最少时间(DP+贪心+正难则反)
Leetcode 第 110 场双周赛 Problem D 2809. 使数组和小于等于 x 的最少时间(DP 好题)题目 给你两个长度相等下标从 0 开始的整数数组 nums1 和 nums2 。每一秒,对于所有下标 0 < i < nums1.length ,nums1[i] 的值都增加 num…...

已知数组A[1..n]中元素类型为非负整数,设计算法将其调整为左右两部分,左边所有为奇数,右边所有为偶数,并要求算法的时间复杂度为O(n)
//左边奇数右边偶数 void Swap(int* a, int* b) {int tmp *b;*b *a;*a tmp; } void LeftRight(int arr[],int n) {int i 0;int j n - 1;while(i<j){if (arr[i] % 2 0 && arr[j] % 2 1) {Swap(&arr[i], &arr[j]);i;j--;}else if (arr[i] % 2 1 &…...

ssm+vue的罪犯信息管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。
演示视频: ssmvue的罪犯信息管理系统(有报告)。Javaee项目,ssm vue前后端分离项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&…...
Java/Android 各类型数据构造和各类型数据解析
Java/Android 各类型数据构造和各类型数据解析 1.如何构造/解析{"key":"value","key":"value","key":"value"}jsonString1)json解析2)fastjson解析3)Gson解析4)遍历key值解析2.如何构造/解析[{"key&q…...

Linux系统---环境变量+内核进程调度队列(选学)
顾得泉:个人主页 个人专栏:《Linux操作系统》 《C/C》 《LeedCode刷题》 键盘敲烂,年薪百万! 一、环境变量 1.基本概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,…...
Kubernetes 使用插件扩展 kubectl
例子演示 编写 kubectl-foo ,拷贝至 /usr/local/bin/ #!/bin/bash# 可选的参数处理 if [[ "$1" "version" ]] thenecho "1.0.0"exit 0 fi# 可选的参数处理 if [[ "$1" "config" ]] thenecho $KUBECONFIGexit…...
前端面试题09
74、定义类的方法有哪些 在JavaScript中,定义类的方法有以下几种方式: 1.使用函数声明: function MyClass() {// constructor } MyClass.prototype.methodName function() {// method body };2.使用类的方法缩写(ES6引入&…...

网站更换IP的四大注意事项
1.对网站当中的数据进行备份 网站更换IP时可以将页面的数据库文件和站点文件通过下载工具在本地完成备份。 2.更换解析域名 从站点域名管理后台当中更换域名地址,改为新的IP地址。 3.确保IP安全 在用户更换IP前一定要确定IP是否安全,一旦IP存在不良…...

策略模式与简单工厂模式:终结if-else混乱,让代码更清爽
阅读建议 嗨,伙计!刷到这篇文章咱们就是有缘人,在阅读这篇文章前我有一些建议: 本篇文章大概4500多字,预计阅读时间长需要5分钟。本篇文章的实战性、理论性较强,是一篇质量分数较高的技术干货文章&#x…...

TCP三次握手过程
什么是TCP tcp是一个面向连接的、可靠的、基于字节流的传输层通信协议 面向连接:TCP连接是一对一的,不能实现一对多或多对一,TCP在通信前要首先建立连接,连接成功后才能开始进行通信可靠的:TCP连接要保证通信过程的可靠…...

04-配置远程仓库的SSH免密登陆
配置SSH免密登录 配置步骤 创建好的远程仓库也可以使用SSH的方式进行访问,但如果没有配置公钥会有警告 第一步: 删除用户家目录下的.ssh目录,如果没有该目录或者该目录下已经有密钥了就不用执行该操作 #进入当前用户的家目录,删除.ssh 目录 LayneLAPTOP-Layne MINGW64 ~ $ r…...

【中文编码】利用bert-base-chinese中的Tokenizer实现中文编码嵌入
最近接触文本处理,查询了一些资料,记录一下中文文本编码的处理方法吧。 先下载模型和词表:bert-base-chinese镜像下载 如下图示,下载好的以下文件均存放在 bert-base-chinese 文件夹下 1. 词编码嵌入简介 按我通俗的…...

一文解决msxml3.dll文件缺失问题,快速修复msxml3.dll
在了解问题之前,我们必须首先清楚msxml3.dll到底是什么。DLL(Dynamic Link Libraries)文件是Windows操作系统使用的一个重要组成部分,用于存储执行特定操作或任务的代码和数据。msxml3.dll为Windows系统提供处理XML文档的功能。如…...

《React 知识点》第一篇 大括号使用{}
简介 大括号 " {} "可以用于包裹JavaScript的表达式或语句。以便在jsx中动态生成内容。 插入变量与表达式 function expressionTest() {const name "变量测试";return (<p><div>{name}</div><div>表达式 210 {2 100}</div…...
kafka入门(二): 位移提交
位移提交: Kafka的每条消息都有唯一的 offset, 用来表示消息在分区中对应的位置。有的也称之为 “偏移量”。 消费者每次在 poll() 拉取消息,它要返回的是还没有消费过的消息集, 因此,需要记录上一次消费时的消费位…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...
MVC 数据库
MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...

Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
React---day11
14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store: 我们在使用异步的时候理应是要使用中间件的,但是configureStore 已经自动集成了 redux-thunk,注意action里面要返回函数 import { configureS…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...
在Ubuntu24上采用Wine打开SourceInsight
1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...