【问题标题】:Grepping a huge file (80GB) any way to speed it up?Grepping一个巨大的文件(80GB)有什么办法可以加快速度?
【发布时间】:2012-12-04 11:32:59
【问题描述】:
 grep -i -A 5 -B 5 'db_pd.Clients'  eightygigsfile.sql

这已经在一个相当强大的 linux 服务器上运行了一个小时,否则不会超载。 grep的任何替代品?关于我的语法有什么可以改进的,(egrep,fgrep 更好?)

该文件实际上位于与挂载到另一台服务器共享的目录中,但实际的磁盘空间是本地的,所以应该没有任何区别?

grep 占用了高达 93% 的 CPU

【问题讨论】:

  • 根据您的语言环境,-i 开关可能会减慢进程,请尝试不使用 -i 或使用 LC_ALL=C grep ...。此外,如果您只是寻找固定字符串,请使用 grep -F
  • 正如@dogbane 提到的那样,使用 LC_ALL=C 变量和 fgrep 可以加快您的搜索速度。我做了一些测试并且能够实现1400% 性能提升,并写了一篇详细的文章为什么这是在我的speed up grep 帖子中
  • 我很好奇 - 80GB 大小的文件是什么?我想当文件变得那么大时,可能会有更好的存储策略(例如轮换日志文件,或按层次分类到不同的文件和文件夹中)。此外,如果更改仅发生在文件的某些位置(例如,在末尾),则只需存储前面部分中未更改的 grep 结果,而不是对原始文件进行 grep,而是对存储的结果文件进行 grep。
  • 我选择了github.com/google/codesearch——索引和搜索都快如闪电(用 Go 编写)。 cindex . 索引您当前的文件夹,然后csearch db_pd.Clients
  • 如果您的文件被索引或排序,这可以大大更快。根据定义,搜索每一行是 O(n),而可以通过将其一分为二来查找已排序的文件——此时你会在一秒钟内搜索你的 80gb(因此为什么一个 80gb 的索引数据库根本不需要时间对于一个简单的选择,而你的 grep 需要......好吧,只要它需要)。

标签: bash grep


【解决方案1】:

这里有几个选项:

1) 在您的 grep 命令前加上 LC_ALL=C 以使用 C 语言环境而不是 UTF-8。

2) 使用fgrep,因为您搜索的是固定字符串,而不是正则表达式。

3) 如果您不需要,请删除 -i 选项。

所以你的命令变成了:

LC_ALL=C fgrep -A 5 -B 5 'db_pd.Clients' eightygigsfile.sql

如果将文件复制到 RAM 磁盘也会更快。

【讨论】:

  • 这快了一个数量级,谢谢。顺便说一句,我添加了 -n 来获取行号。也可能是 -m 在比赛结束后退出
  • 哇非常感谢@dogbane 很棒的提示!这让我沿着研究隧道找到了why LC_ALL=C speeds up grep,这是一次非常有启发性的经历!
  • 有些人(不是我)喜欢grep -F 超过fgrep
  • 我的理解是LANG=C(而不是LC_ALL=C)就足够了,而且更容易打字。
  • @Adrian fgrep 是写grep -F 的另一种方式,man fgrep 会告诉你。 man 的某些版本还说前者已被后者弃用,但较短的形式太方便死了。
【解决方案2】:

如果你有一个多核 CPU,我真的会推荐 GNU parallel。要并行使用 grep 大文件:

< eightygigsfile.sql parallel --pipe grep -i -C 5 'db_pd.Clients'

根据您的磁盘和 CPU,读取更大的块可能会更快:

< eightygigsfile.sql parallel --pipe --block 10M grep -i -C 5 'db_pd.Clients'

您的问题并不完全清楚,但grep 的其他选项包括:

  • 删除-i 标志。
  • -F 标志用于固定字符串
  • 使用LANG=C 禁用 NLS
  • 使用-m 标志设置最大匹配数。

【讨论】:

  • 如果是实际文件,请使用--pipepart 而不是--pipe。它要快得多。
  • 这种用法不支持包含空格的模式,我们需要这样使用:parallel --pipe --block 10M "/usr/bin/grep -F -C5 -e 'Animal Care & Pets'"
  • 并行命令前面的&lt; 字符是什么意思?
  • @elcortegano:这就是所谓的I/O redirection。基本上,它从以下文件名读取输入。类似于cat file.sql | parallel ...,但避免使用UUOC。 GNU 并行还可以使用parallel ... :::: file.sql 从文件中读取输入。 HTH。
  • 如果我想 grep 整个文件目录怎么办?
【解决方案3】:

一些微不足道的改进:

  • 去掉 -i 选项,如果可以的话,不区分大小写很慢。

  • . 替换为\.

    单点就是匹配任意字符的正则符号,也很慢

【讨论】:

    【解决方案4】:

    两条攻击线:

    • 你确定,你需要-i,还是你有可能摆脱它?
    • 你有更多的内核可以玩吗? grep 是单线程的,因此您可能希望以不同的偏移量启动更多它们。

    【讨论】:

      【解决方案5】:
      < eightygigsfile.sql parallel -k -j120% -n10 -m grep -F -i -C 5 'db_pd.Clients'  
      

      如果您需要搜索多个字符串,grep -f strings.txt 可以节省大量时间。以上是我目前正在测试的内容的翻译。 -j 和 -n 选项值似乎最适合我的用例。 -F grep 也有很大的不同。

      【讨论】:

        【解决方案6】:

        试试ripgrep

        与 grep 相比,它提供了更好的结果。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-12-03
          • 1970-01-01
          • 2012-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-08-16
          相关资源
          最近更新 更多