对大分隔文件进行聚合操作的 Powershell 性能调整

Powershell Performance tuning for aggregation operation on big delimited files

我有一个包含 350 列的分隔文件。分隔符是 4(Field separator)。 我必须提取特定的列值并找出文件中该列的每个不同值的计数。如果不同值的计数大于或等于 2,我需要将其输出到文件中。 源文件为1GB。我写了以下命令。速度很慢。

    Get-Content E:\Test\test.txt | Foreach {($_ -split '4')[117]} | Group-Object -Property { $_ } | %{ if($_.Count -ge 2) { Select-Object -InputObject $_ -Property Name,Count} } | Export-csv -Path "E:\Test\test2.csv" -NoTypeInformation

请帮忙!

我建议使用 switch statement 来快速处理输入文件(按照 PowerShell 标准):

# Get an array of all the column values of interest.
$allColValues = switch -File E:\Test\test.txt {
  default {  # each input line
    # For better performance with *literal* separators, 
    # use the .Split() *method*.
    # Generally, however, use of the *regex*-based -split *operator* is preferable.
    $_.Split([char] 0x1c)[117] # hex 0x1c is octal 034
  }
}

# Group the column values, and only output those that occur at least 
# twice.
$allColValues | Group-Object -NoElement | Where-Object Count -ge 2 |
  Select-Object Name, Count | Export-Csv E:\Test\test2.csv -NoTypeInformation

Mathias R. Jessen 致敬,建议使用 -NoElement 开关,它通过仅维护 abstract[= 简化了 Group-Object 调用64=]组信息;也就是说,仅返回分组 criteria(如 .Name 中所反映的那样),而不是组成该组的单个对象(通常如 .Group 中所反映的那样)通过输出对象。


至于你试过的

  • Get-Content 管道中的逐行流 一般 (逐个对象传递会引入开销)并且,特别是,因为Get-Content 用 ETS(扩展类型系统)元数据装饰它输出的每一行。

    • GitHub issue #7537 建议添加一种方法来选择退出此装饰。
    • 以内存消耗和可能的行拆分额外工作为代价,-Raw 开关将 整个文件 作为单个多行字符串读取,这要快得多。
  • 不需要将 -Property { $_ } 传递给 Group-Object - 忽略它即可。没有 -Property 参数,输入对象被分组 作为一个整体 .

  • 链接 Where-Object and Select-Object - rather than filtering via an if statement in a ForEach-Object 调用与 多个 Select-Object 调用相结合 - 不仅在概念上更清晰,而且性能更好。