根据列值拆分大文件并使用关闭命令时 AWK 非常慢
AWK very slow when splitting large file based on column value and using close command
我需要根据第一列中找到的 ID 将一个大日志文件拆分成多个较小的日志文件,这个解决方案在几个月内效果非常好并且非常快:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"}' ${nome}.all;
其中 $nome 是文件名和目录名。
速度非常快,直到日志文件达到几百万行+2GB 文本文件,然后才开始显示
"Too many open files"
解决方法确实很简单,加上关闭命令:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"; close(dir"/"dir"_"".log")}' ${nome}.all;
问题是,现在它非常慢,它需要很长时间才能完成几秒钟内完成的事情,我需要对此进行优化。
AWK 不是强制性的,我可以使用替代方法,只是不知道如何使用
未经测试,因为您没有提供任何样本 input/output 进行测试,但应该这样做:
sort -t';' -k1,1 "${nome}.all" |
awk -v dir="$nome" -F\; '!=prev{close(out); out=dir"/"dir"_"".log"; prev=} {print > out}'
您的第一个脚本:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"}' ${nome}.all;
有 3 个问题:
- 它没有关闭文件名,因此超出了您看到的阈值。
- 它在输出重定向的右侧有一个未加括号的表达式,根据 POSIX.
,这是未定义的行为
- 它没有在文件名中引用 shell 变量
${nome}
。
值得一提的是,gawk 能够处理 1 和 2 而不会失败,但是随着打开文件数量的增加它会变慢并且它必须在内部管理 opens/closes。
你的第二个脚本:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"; close(dir"/"dir"_"".log")}' ${nome}.all;
虽然现在关闭输出文件名,但问题 2 和 3 仍然存在,然后添加了 2 个新问题:
- 每个输入行打开和关闭输出文件一次,而不是仅在必须更改输出文件名时才打开和关闭一次。
- 它正在为写入的每一行每 $1 覆盖输出文件,而不是附加到它。
上面假设每个 $1 有多行输入,因此每个输出文件都有多行。否则,您在关闭输出文件时看到的减速就不会发生。
上面的sort
可以重新排列每个$1的输入行的顺序。如果这是一个问题,请为“稳定排序”添加 -s
(如果您有 GNU 排序)或让我们知道,因为使用 POSIX 工具很容易解决。
我需要根据第一列中找到的 ID 将一个大日志文件拆分成多个较小的日志文件,这个解决方案在几个月内效果非常好并且非常快:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"}' ${nome}.all;
其中 $nome 是文件名和目录名。
速度非常快,直到日志文件达到几百万行+2GB 文本文件,然后才开始显示
"Too many open files"
解决方法确实很简单,加上关闭命令:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"; close(dir"/"dir"_"".log")}' ${nome}.all;
问题是,现在它非常慢,它需要很长时间才能完成几秒钟内完成的事情,我需要对此进行优化。
AWK 不是强制性的,我可以使用替代方法,只是不知道如何使用
未经测试,因为您没有提供任何样本 input/output 进行测试,但应该这样做:
sort -t';' -k1,1 "${nome}.all" |
awk -v dir="$nome" -F\; '!=prev{close(out); out=dir"/"dir"_"".log"; prev=} {print > out}'
您的第一个脚本:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"}' ${nome}.all;
有 3 个问题:
- 它没有关闭文件名,因此超出了您看到的阈值。
- 它在输出重定向的右侧有一个未加括号的表达式,根据 POSIX. ,这是未定义的行为
- 它没有在文件名中引用 shell 变量
${nome}
。
值得一提的是,gawk 能够处理 1 和 2 而不会失败,但是随着打开文件数量的增加它会变慢并且它必须在内部管理 opens/closes。
你的第二个脚本:
awk -v dir="$nome" -F\; '{print>dir"/"dir"_"".log"; close(dir"/"dir"_"".log")}' ${nome}.all;
虽然现在关闭输出文件名,但问题 2 和 3 仍然存在,然后添加了 2 个新问题:
- 每个输入行打开和关闭输出文件一次,而不是仅在必须更改输出文件名时才打开和关闭一次。
- 它正在为写入的每一行每 $1 覆盖输出文件,而不是附加到它。
上面假设每个 $1 有多行输入,因此每个输出文件都有多行。否则,您在关闭输出文件时看到的减速就不会发生。
上面的sort
可以重新排列每个$1的输入行的顺序。如果这是一个问题,请为“稳定排序”添加 -s
(如果您有 GNU 排序)或让我们知道,因为使用 POSIX 工具很容易解决。