SQL日志落库高性能核心是解耦与缓冲:日志生成与DB写入分离,通过消息队列异步中转,消费者批量有序落库;精简表结构、禁用冗余索引、启用压缩与预编译;本地缓冲兜底保可靠。

SQL日志落库的高性能核心在于“解耦”和“缓冲”——把日志生成与数据库写入彻底分开,避免业务线程被IO拖慢。
用消息队列做异步中转
日志不直接INSERT,而是发到Kafka/RocketMQ等消息队列。业务线程毫秒级返回,写入由独立消费者进程批量、有序、可控地落库。
- 消费者按表/日志类型分组消费,避免跨表事务干扰
- 单批次控制在500~2000条,兼顾吞吐与内存压力
- 启用消息压缩(如snappy),降低网络和磁盘IO开销
批量插入 + 预编译语句
消费者端不单条执行INSERT,改用批量操作,配合PreparedStatement复用执行计划。
- MySQL用INSERT INTO ... VALUES (...), (...), (...)一次性插多行
- PostgreSQL用INSERT INTO ... SELECT ... UNION ALL ...或COPY协议
- 开启rewriteBatchedStatements=true(MySQL JDBC)自动重写批处理
日志表结构与索引精简
日志表不是业务表,不做复杂查询,要为写入而设计。
- 主键用自增ID或时间戳+序列号,避免UUID导致的随机写入
- 只保留必要字段,TEXT/BLOB类大字段单独拆表或存OSS
- 除主键外尽量不建索引;如需按时间查,用分区表(按天/月分区)替代全局索引
本地缓冲 + 落盘兜底
极端情况下消息队列不可用,也不能丢日志。加一层本地磁盘缓冲(如RocksDB或带刷盘的环形文件队列)。
- 业务线程先写本地缓冲(毫秒级),再异步投递到MQ
- 缓冲区满或定时(如3s)触发批量投递,失败则保留在本地待重试
- 服务重启时自动加载未投递日志,保证至少一次语义
基本上就这些。不复杂但容易忽略的是:别让日志写入路径参与业务事务,也别在高并发接口里做任何同步DB操作——日志的使命是记录,不是阻塞。











