我有一个从 Teradata 记录导出的 4TB 大文本文件,我想知道该文件中有多少条记录(= 在我的情况下为行)。
我怎样才能快速有效地做到这一点?
答案1
如果此信息尚未作为元数据存在于单独的文件中(或嵌入在数据中,或通过查询从中导出数据的系统可用),并且没有可用的某种描述的索引文件,则最快的方法来计算数量线是通过wc -l
在文件上使用。
你确实无法做得更快。
来计算数量记录在文件中,您必须知道使用的记录分隔符并使用类似的方法awk
来计算它们。同样,如果此信息尚未作为元数据存储在其他地方,并且如果无法通过对原始系统的查询获得该信息,并且如果记录本身尚未在文件中枚举和排序。
答案2
所以这里是awk和wc之间的速度测试
67G测试.tsv
time awk 'END {print NR}' test.tsv; time wc -l test.tsv
809162924
real 2m22.713s
user 1m46.712s
sys 0m19.618s
809162924 test.tsv
real 0m20.222s
user 0m9.629s
sys 0m10.592s
另一个文件72G Sample.sam
time awk 'END {print NR}' Sample.sam; time wc -l Sample.sam
180824516
real 1m18.022s
user 1m5.775s
sys 0m12.238s
180824516 Sample.sam
real 0m22.534s
user 0m4.599s
sys 0m17.921s
答案3
您不应使用基于行的实用程序,例如awk
和sed
。这些实用程序将为read()
输入文件中的每一行发出系统调用(请参阅回答为什么会这样)。如果你有很多行,这将是一个巨大的性能损失。
由于你的文件大小为 4TB,我猜有很多行。因此,甚至wc -l
会产生大量read()
系统调用,因为它16384
每次调用仅读取字节(在我的系统上)。无论如何,这将是对awk
和 的改进sed
。最好的方法 - 除非你编写自己的程序 - 可能就是
cat file | wc -l
这对 cat 来说并不是无用的,因为每次系统调用都会cat
读取字节块(在我的系统上),并且会发出更多字节,但不是直接在文件上,而是在管道上。但是,每次系统调用都会尝试尽可能多地读取数据。131072
read()
wc -l
cat
答案4
我还对大型 VCF 文本文件进行了速度比较。这是我发现的:
216GB VCF 文本文件(在单个 SSD 上)
$ time wc -l <my_big_file>
16695620
real 1m26.912s
user 0m2.896s
sys 1m23.002s
$ tail -5 <my_big_file>
$ time fgrep -n <last_line_pattern> <my_big_file>
16695620:<last_line_pattern>
real 2m10.154s
user 0m46.938s
sys 1m22.492s
$ tail -5 <my_big_file>
$ LC_ALL=C && time fgrep -n <last_line_pattern> <my_big_file>
16695620:<last_line_pattern>
real 1m38.153s
user 0m45.863s
sys 0m51.944s
最后:
$ time awk 'END {print NR}' <my_big_file>
16695620
real 1m44.074s
user 1m11.275s
sys 0m32.780s
结论一:
wc -l
SSD 似乎最快。
216GB VCF 文本文件(在具有 8 个 HDD 的 RAID10 设置上)
$ time wc -l <my_big_file>
16695620
real 7m22.397s
user 0m10.562s
sys 4m1.888s
$ tail -5 <my_big_file>
$ time fgrep -n <last_line_pattern> <my_big_file>
16695620:<last_line_pattern>
real 7m7.812s
user 1m58.242s
sys 3m12.355s
$ tail -5 <my_big_file>
$ LC_ALL=C && time fgrep -n <last_line_pattern> <my_big_file>
16695620:<last_line_pattern>
real 4m34.522s
user 1m26.764s
sys 1m58.247s
最后:
$ time awk 'END {print NR}' <my_big_file>
16695620
real 6m50.240s
user 2m37.574s
sys 2m43.498s
结论2:
wc -l
看起来与其他人相当。- 较低的时间
LC_ALL=C && time fgrep -n <last_line_pattern>
很可能是由于缓存造成的,因为后续wc -l
也显示了较低的时间。