8.4 SQL 操作与报表输出


8.4 SQL 操作与报表输出

本节给全书主线收尾:把日志统计写进表、用 SQL 聚合查询、以"HTML 报表 + 文本摘要"两种形态输出。凌晨两点被磁盘报警叫醒的那个你,现在手里有一条全自动的答案生产线。

建表与入库

$dbh->do('CREATE TABLE IF NOT EXISTS access_log ( id INTEGER PRIMARY KEY AUTOINCREMENT, log_date TEXT, ip TEXT, api TEXT, status INTEGER, ms INTEGER )'); my $ins = $dbh->prepare( 'INSERT INTO access_log (log_date, ip, api, status, ms) VALUES (?,?,?,?,?)' );

逐行入库后,"哪些接口最慢"从 Perl 循环问题变成一条 SQL:

my $slow = $dbh->selectall_arrayref( 'SELECT api, COUNT(*) n, AVG(ms) avg_ms FROM access_log WHERE status < 400 GROUP BY api ORDER BY avg_ms DESC LIMIT 10', { Slice => {} }, );

能在 SQL 里做的聚合不搬回 Perl——数据库的聚合引擎有索引加持,代码还短一截。Perl 端聚合与 SQL 端聚合的分工:流式单遍统计(边读边算)用哈希,事后多维度查询入库后用 SQL。

产出双形态报告

open my $txt, '>', 'report.txt' or die $!; printf $txt "慢接口 Top10(%s)\n\n", scalar localtime; print $txt "$$_{api}\t$$_{n}次\t平均$$_{avg_ms}ms\n" for @$slow; open my $html, '>', 'report.html' or die $!; print $html "<html><body><h2>慢接口 Top10</h2><table border=1>", map("<tr><td>$_->{api}</td><td>$_->{n}</td><td>$_->{avg_ms}</td></tr>", @$slow), "</table></body></html>";

文本给值班群,HTML 给浏览器——同一份 $slow 数据两种渲染,输出形态只是格式化问题。

全书主线的最终架构

全书主线的最终架构

💡 关键直觉:报表脚本要可重跑。入库前按日期加唯一约束或先删后插,同一批日志跑两遍结果一致——幂等性是自动化信任的起点。

幂等入库的落地写法

直觉的落地是"先删后插"两步走,配合事务保证原子:

$dbh->{AutoCommit} = 0; my $ok = eval { $dbh->do('DELETE FROM access_log WHERE log_date = ?', undef, $date); $ins->execute(@$_) for @rows; $dbh->commit; 1; }; $dbh->rollback unless $ok; # 删了没插上?一起回滚 $dbh->{AutoCommit} = 1;

重跑同一日期等于覆盖当日数据,脚本报错也不会留下半日数据。另一个配套细节是建表时给 log_date 加索引——DELETE 按日期定位没索引的话,表一大每次重跑都是全表扫,幂等设计反而成了性能负担。

从报表到告警:最后一步自动化

报表给人看,告警给系统看,最后一步是把"超过阈值"变成主动通知。在报表脚本尾部加一段判断,超标时写告警文件或调用通知接口:

my @alert = grep { $_->{avg_ms} > 1000 } @$slow; if (@alert) { open my $af, '>', "alert_$date.txt" or warn $!; printf $af "[慢接口告警] %s 平均 %dms\n", $_->{api}, $_->{avg_ms} for @alert; }

告警的去重与升级(同一接口连续三天超标才升级)属于告警系统自身的设计,报表脚本只负责如实产出"今日超标清单"。至此全流程闭环:日志进、报表出、异常有人知——凌晨两点的报警电话,从此变成早上九点的一份邮件。

终检清单:交付前过一遍

全书交付前,把主线脚本按这张清单终检一遍,每条都对应前文某个章节的纪律:解析内核有测试覆盖且全绿(第 7 章);错误按分级策略处理,前置校验齐全(第 7 章);批量操作断点可续跑(第 5 章);产出走临时文件加原子改名(第 5 章);模块接口窄、文档有 SYNOPSIS(第 6 章);外部调用全带超时与列表传参(第 8 章);数据库操作占位符无例外、事务包裹、幂等可重跑(第 8 章);依赖与版本记录在案(第 6 章)。八条全过,脚本就从"能跑的代码"变成了"可交接的资产"——任何人接手,看文档知用法、跑测试验现状、读日志明历史。这也是本书把工程纪律与语法并重的最后用意:语法决定你能不能写出来,纪律决定它能不能活下去。合上本书,工坊的灯不灭——你的下一份文本原料已在门外排队。若想再回炉某个零件,按需直达:正则回第 4 章、流水线回第 5 章、装箱回第 6 章、质检回第 7 章、对外窗口回本章,全书的知识地图就是你的返修手册。工坊交付,开工愉快——愿你的正则永不回溯,日志永远可解析,报表每次准点送达。也把最后的实操作业留下:拿你手边任意一份真实日志,从第 1 章的统计行数开始,一路做到本节的入库与告警——走完这条完整流水线,工坊的八年功力就真正长在了你的手上,而不只是这本书里。到那时再翻开第 1 章那个凌晨两点的故事,你会会心一笑:报警还在,但答案早已自动送达。

本节要点回顾

  • 聚合能下放 SQL 就下放,Perl 哈希只做流式单遍场景
  • 同一数据多种渲染,文本与人看、HTML 给浏览器
  • 建表带约束、入库可重跑,幂等是自动化的地基
  • 慢接口 Top N 一条 SQL,比循环排序好维护
  • 全书主线在此闭环:目录进、报表出,中间每章一个可复用零件

作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U