更快的迭代

时间:2018-10-07 22:44:37

标签: performance powershell foreach iteration

我有这段代码,它是根据时间范围返回SQL行列表的函数的一部分。

查询本身(第一行代码)非常快。但是提取相关数据的foreach循环需要一段时间才能完成。

我有大约350.000行要迭代,尽管要花一些时间,但我想知道是否可以进行任何更改以使其更快。

$SqlDocmasterTableResuls = $this.SqlConnection.GetSqlData("SELECT DOCNUM, DOCLOC FROM MHGROUP.DOCMASTER WHERE ENTRYWHEN between '" + $this.FromDate + "' and '" + $this.ToDate + "'")

[System.Collections.ArrayList]$ListOfDocuments = [System.Collections.ArrayList]::New()

if ($SqlDocmasterTableResuls.Rows.Count)
{
    foreach ($Row in $SqlDocmasterTableResuls.Rows)
    {
        $DocProperties = @{
            "DOCNUM"      = $Row.DOCNUM
            "SOURCE"      = $Row.DOCLOC
            "DESTINATION" = $Row.DOCLOC -replace ([regex]::Escape($this.iManSourceFileServerName + ":" + $this.iManSourceFileServerPath.ROOTPATH)),
                            ([regex]::Escape($this.iManDestinationFileServerName + ":" + $this.iManDestinationFileServerPath.ROOTPATH))
        }

        $DocObj = New-Object -TypeName PSObject -Property $DocProperties
        $ListOfDocuments.Add($DocObj)
    }

    return $ListOfDocuments

2 个答案:

答案 0 :(得分:4)

避免在循环中附加到数组。捕获变量中循环数据的最好方法是简单地将循环输出收集到变量中:

$ListOfDocuments = foreach ($Row in $SqlDocmasterTableResuls.Rows) {
    New-Object -Type PSObject -Property @{
        "DOCNUM"      = $Row.DOCNUM
        "SOURCE"      = $Row.DOCLOC
        "DESTINATION" = $Row.DOCLOC -replace ...
    }
}

您不需要周围的if有条件,因为如果表没有任何行,则循环应跳过该行,而结果为空。

由于无论如何都要返回列表,因此甚至不需要将循环输出收集到变量中。只需保留输出不变,无论如何它将得到返回。

当结果不变时,也要避免在循环中重复操作。在循环之前计算一次转义的源路径和目标路径:

$srcPath = [regex]::Escape($this.iManSourceFileServerName + ':' + $this.iManSourceFileServerPath.ROOTPATH)
$dstPath = [regex]::Escape($this.iManDestinationFileServerName + ':' + $this.iManDestinationFileServerPath.ROOTPATH)

并在循环内使用变量$srcPath$dstPath

类似的事情应该做:

$SqlDocmasterTableResuls = $this.SqlConnection.GetSqlData("SELECT ...")

$srcPath = [regex]::Escape($this.iManSourceFileServerName + ':' + $this.iManSourceFileServerPath.ROOTPATH)
$dstPath = [regex]::Escape($this.iManDestinationFileServerName + ':' + $this.iManDestinationFileServerPath.ROOTPATH)
foreach ($Row in $SqlDocmasterTableResuls.Rows) {
    New-Object -Type PSObject -Property @{
        'DOCNUM'      = $Row.DOCNUM
        'SOURCE'      = $Row.DOCLOC
        'DESTINATION' = $Row.DOCLOC -replace $srcPath, $dstPath
    }
}

return

答案 1 :(得分:0)

[编辑-根据Ansgar Wiechers,PSCO加速器仅适用于ps3 +。]

另一件事可能有用,就是将New-Object替换为[PSCustomObject]。通常使用起来会更快。像这样的东西...

$DocObj = [PSCustomObject]$DocProperties

使用该类型加速器的另一种方法是执行Ansgar Wiechers在他的代码示例中所做的事情,但是使用加速器而不是cmdlet。这样...

[PSCustomObject]@{
    'DOCNUM'      = $Row.DOCNUM
    'SOURCE'      = $Row.DOCLOC
    'DESTINATION' = $Row.DOCLOC -replace $srcPath, $dstPath
    }

希望有帮助,