应禁用 general_log,改用 audit_log 插件(企业版)或 mysqlbinlog 解析 ROW/MIXED 格式 binlog;PostgreSQL 用 pg_audit 配 log_parameter=on 并配置日志采集;SQL Server 必用 sys.fn_get_audit_file() 读取 .sqlaudit 文件;所有场景须统一时区与时间格式处理。

MySQL 8.0 开启 general_log 后导出审计日志太慢怎么办
直接用 general_log 记录所有 SQL 会严重拖慢数据库性能,尤其在高并发写入场景下,日志写入本身就成了瓶颈。它不是为审计设计的,而是调试用的临时开关。
真正可落地的做法是启用 audit_log 插件(需企业版)或用 mysqlbinlog 解析二进制日志——后者免费、稳定、粒度可控。
-
audit_log插件默认只记录连接/断开和权限类事件,要记录 DML/DDL 必须显式配置audit_log_policy = ALL和audit_log_include_accounts - 用
mysqlbinlog --base64-output=DECODE-ROWS -v解析 binlog,能还原出完整语句(含参数化后的值),但需开启binlog_format = ROW或MIXED - 不要用
SELECT * FROM mysql.general_log导出——表引擎是 CSV,无索引,10 万行以上就卡死
PostgreSQL 如何用 pg_audit 插件生成合规审计报表
pg_audit 是最接近“开箱即用”的方案,但它默认不记录执行结果、不记录绑定变量,且日志分散在 PostgreSQL 的 log 目录里,不是结构化表。
关键在于配置阶段就得想清楚:你要审的是谁、什么操作、到哪一级别。比如只关心 public 模式下的 UPDATE,就不能笼统设 log_statement = 'all',否则日志爆炸且混杂无关信息。
- 必须设置
shared_preload_libraries = 'pg_audit'并重启,热加载无效 -
pg_audit.log_parameter = on才能看到实际传入的参数值,否则只有$1, $2占位符 - 日志默认走
log_destination = 'stderr',要导出报表得先配logging_collector = on+log_directory,再用logrotate定期切分 - 报表脚本建议用
awk或pgbadger解析,别自己写正则匹配——pg_audit日志格式有嵌套括号和换行,正则极易漏判
SQL Server 审计日志导出时提示 “The audit log is not available”
这个错误通常不是日志丢了,而是你查错了位置。SQL Server 的服务器级审计日志默认存在 Windows 事件日志里(Security 或 Application),不是在数据库表中;而数据库级审计日志虽然存成 .sqlaudit 文件,但路径受 SQL Server 服务账户权限限制,不一定能被你的登录账号读取。
更隐蔽的问题是:审计规范要求“不可篡改”,所以 SQL Server 默认把日志写成只读文件,且不支持直接 SELECT 查询——必须用 sys.fn_get_audit_file() 函数加载。
- 检查
sys.server_audits状态是否为ON,状态为PENDING表示日志文件已满或磁盘满 - 用
sys.fn_get_audit_file('X:\path\to\*.sqlaudit', default, default)查,路径必须带通配符,不能指定单个文件名 - 如果返回空结果,先确认 SQL Server 服务账户对目标目录有
Read & Execute权限,普通 Windows 登录用户默认没这权限 - 导出报表时别用 SSMS 的“结果另存为”,字段含 XML 类型会截断;改用
bcp命令或 PowerShell 的Export-Csv
审计报表定时导出后发现时间戳全乱了
几乎所有数据库审计日志的时间戳都依赖系统时钟,但真正出问题的地方往往不在数据库本身,而在日志采集链路的中间环节:比如用 rsyslog 转发 PostgreSQL 日志时未启用 $ActionFileDefaultTemplate RSYSLOG_FileFormat,导致毫秒级精度丢失;或者 SQL Server 的 fn_get_audit_file 返回的 event_time 是 UTC,而你的报表脚本硬编码了 GETDATE() 当本地时间处理。
- MySQL
binlog时间戳是写入时的 server time,但mysqlbinlog解析后默认显示本地时区,加--base64-output=DECODE-ROWS --verbose可看到原始timestamp字段 - PostgreSQL
pg_audit的log_line_prefix必须包含%m(毫秒)和%z(时区),否则跨时区团队看报表会误判操作顺序 - 导出脚本里所有时间转换统一走
CONVERT(datetime2, ..., 127)(SQL Server)或TO_TIMESTAMP(..., 'YYYY-MM-DD HH24:MI:SS.US')(PostgreSQL),别依赖隐式转换
时间对不上这事,90% 发生在日志从源头到报表之间至少经过两次时区转换,而且没人校验中间环节的输出格式。盯住第一个落盘的日志文件头,比后期修数据强十倍。










