【问题标题】:PowerShell - Group-Object Poor PerformancePowerShell - 组对象性能不佳
【发布时间】:2022-10-25 12:04:51
【问题描述】:

我编写了一个脚本来帮助我识别重复文件。出于某种原因,如果我拆分这些命令并将其导出/导入到 CSV,它的运行速度要比将所有内容都留在内存中要快得多。这是我的原始代码,速度太慢了:

Get-ChildItem M:\ -recurse | where-object {$_.length -gt 524288000} | select-object Directory, Name | Group-Object directory | ?{$_.count -gt 1} | %{$_.Group} | export-csv -notypeinformation M:\Misc\Scripts\Duplicates.csv

如果我把它分成 2 个命令并在中间导出到 CSV,它的运行速度大约快 100 倍。我希望有人可以阐明我做错了什么。

Get-ChildItem M:\ -recurse | where-object {$_.length -gt 524288000} | select-object Directory, Name | Export-Csv -notypeinformation M:\Misc\Scripts\DuplicateMovies\4.csv

import-csv M:\Misc\Scripts\Duplicates\4.csv | Group-Object directory | ?{$_.count -gt 1} | %{$_.Group} | export-csv -notypeinformation M:\Misc\Scripts\Duplicates\Duplicates.csv

remove-item M:\Misc\Scripts\Duplicates\4.csv

感谢任何建议,

~TJ

【问题讨论】:

  • 我很难相信导出到文件然后再导入过滤比只在内存中执行所有操作更快。而且,select-object Directory, Name 定位错误,应该是导出前的最后一步。
  • 我很早就做了选择,因为我希望在脚本的早期删除一些其他属性会加快速度——例如,我不关心 LastWriteTime。我刚才把 select-object 放在最后,但没有发现任何区别。父文件夹有大约 10K 子文件夹,特别是脚本的组对象部分需要永远 - 我在等待 20 分钟后放弃了,而当我使用 CSV 文件时,组对象需要 10 秒。
  • 这是 PowerShell 5.1 还是 PowerShell Core 7+?另外,您应该注意,.Directory 不仅仅是一个字符串,它本身就是一个 DirectoryInfo 对象,如果您尝试使用太多文件进行此操作,那么它是巨大的(在您的 Get-ChildItem 调用中也缺少 -File)。此外,您确定文件是否重复的条件似乎很奇怪,按父文件夹对对象进行分组如何帮助您确定它们是否重复?
  • 确定文件是否重复的最佳方法是对它们进行 MD5sum,或者更麻烦但更快,顺序读取字节并比较它们

标签: powershell group-object


【解决方案1】:

慢的不是Group-Object,这是您的分组条件,您要求它按 .Directory property 代表其父文件夹 DirectoryInfo 实例对 FileInfo 对象进行分组。所以,您要求 cmdlet 按非常复杂的对象对对象进行分组作为分组条件, 而您可以使用 .DirectoryName property 作为分组条件,它代表父目录的 FullName 属性(一个简单的字符串),或者您可以使用 .Directory.Name property 代表父文件夹的 Name (也是一个简单的字符串) .

总而言之,在这种情况下,导出到 CSV 的速度更快的主要原因是,当Export-Csv 从管道接收您的对象时,它会在每个对象的属性值上调用ToString() 方法,因此Directory 实例被转换到它的字符串表示形式(调用ToString() to this instance ends up being the folder's FullName)。

至于您的代码,如果您想保持尽可能高效而又不使其过于复杂:

Get-ChildItem M:Movies -Recurse -File | & {
    process {
        if($_.Length -gt 500mb) { $_ }
    }
} | Group-Object DirectoryName | & {
    process {
        if($_.Count -gt 2) {
            foreach($object in $_.Group) {
                [pscustomobject]@{
                    Directory = $_.Name # => This is the Parent Directory FullName
                    Name      = $object.Name
                }
            }
        }
    }
} | Export-Csv M:MiscScriptsDuplicateMovies.csv -NoTypeInformation

如果您想按父 Name 而不是 FullName 对它们进行分组,您可以使用:

Group-Object { $_.Directory.Name }

【讨论】:

  • 这对我来说是按预期工作的,只需对组对象进行简单更改。我很欣赏这些建议。最终代码 = Get-ChildItem M:Movies -recurse | where-object {$_.length -gt 524288000} | select-object Directory, Name | Group-Object { $_.Directory.Name } | ?{$_.count -gt 1} | %{$_.Group} | export-csv -notypeinformation M:MiscScriptsDuplicateMoviesDuplicatemovies.csv
猜你喜欢
  • 1970-01-01
  • 2020-06-10
  • 2019-02-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-27
  • 1970-01-01
  • 2014-03-18
相关资源
最近更新 更多