大日志文件PO编号查询脚本优化请求:缩短2.45小时执行时长
优化大日志文件中多PO编号统计的执行效率
兄弟,你的脚本慢得离谱的核心原因一眼就能看出来——你循环调用了11k+次grep,每次都要把500-600MB的日志文件从头到尾读一遍,磁盘IO的开销直接拉满,不慢才怪!咱们换个思路:只把日志文件读一次,就能完成所有PO的统计,效率能提升几十甚至上百倍。
方案1:用awk一次性处理(最推荐,性能最优)
awk可以一次性把所有PO编号加载到内存,然后遍历一次日志文件完成统计,全程只需要读一次日志和一次PO列表,把磁盘IO开销降到最低。
直接用这个脚本替换你的循环:
awk -v po_list="po_numbers" ' BEGIN { # 先把所有PO编号加载到关联数组,初始计数设为0 while ((getline po < po_list) > 0) { count[po] = 0 } close(po_list) } # 遍历日志每一行,匹配到PO_NUMBER字段就提取编号并计数 /PO_NUMBER=/ { split($0, parts, "PO_NUMBER=") po = parts[2] # 只统计在我们目标列表里的PO if (po in count) { count[po]++ } } # 处理完所有日志后,输出结果到指定文件 END { for (po in count) { print po "-->" count[po] >> "list3" if (count[po] == 0) { print po >> "po_to_server" } } } ' Test.log
这个脚本的执行时间应该能从几小时直接压缩到几分钟甚至几十秒,完全不是一个量级的提升。
方案2:用grep的-f选项批量匹配(更简洁)
如果你对awk不太熟悉,也可以用grep的批量匹配功能,同样只读一次日志:
# 第一步:批量匹配所有目标PO的行,提取PO编号后统计出现次数 grep -o "PO_NUMBER=\([^[:space:]]*\)" Test.log | grep -f <(sed 's/^/PO_NUMBER=/' po_numbers) | cut -d'=' -f2 | sort | uniq -c > temp_counts # 第二步:和原PO列表对比,生成最终的统计文件和未找到的PO列表 awk 'NR==FNR {count[$2]=$1; next} { print $0 "-->" (count[$0] ? count[$0] : 0) >> "list3" if (!count[$0]) print $0 >> "po_to_server" }' temp_counts po_numbers # 清理临时文件 rm temp_counts
这个方案的性能比awk稍逊一筹,但比你的原脚本快太多,而且写法更贴近你熟悉的grep命令。
原脚本的性能瓶颈拆解
最后给你理清楚为什么原脚本这么慢:
- 磁盘IO爆炸:每次循环都要重新打开、读取、关闭500MB的日志文件,11k次循环就是11k次磁盘IO,这是最慢的操作
- 进程创建开销:每次调用
grep都会创建一个新进程,11k次进程创建的开销累积起来也相当可观
内容的提问来源于stack exchange,提问作者Rasesh
相关产品推荐
相关产品推荐

