У меня есть этот код, который является частью функции, которая возвращает список строк SQL на основе временного диапазона.
Сам запрос (1-я строка кода) довольно быстрый. Но цикл 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
@Russell запрос занимает максимум 10 секунд ... Я уже отладил код, и это занимает около 5 минут в foreach. спасибо
круто - еще одна вещь, которую нужно проверить, - это попытаться удалить 2 строки с сопоставлением регулярных выражений, чтобы они не вызывали задержку.
@Russell Я уже думал об этом, но мне нужно это изменение. Еще попробую удалить, чтобы увидеть результат.
Ну ... особой разницы. Собственно вроде точно так же :(
Это выглядит пугающе уязвимым для атак с использованием sql-инъекций.
@JoelCoehoorn, ты абсолютно прав. Я поменяю позже. Просто тестирую tnks
Никогда не тестировал. Но мне интересно, быстрее ли пересылка $ SqlDocmasterTableResuls.Rows в foreach. Сделайте первую строчку $row = $_
Слишком часто «поменяй потом» превращайся «никогда не меняй».


Избегайте добавления к массиву в цикле. Лучший способ записать данные цикла в переменную - просто собрать выходные данные цикла в переменной:
$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
Спасибо за советы. Я попробую. Но при замене регулярного выражения мне нужно включить его в цикл, потому что оно основано на значении, полученном из таблицы, оно никогда не бывает одинаковым, это путь к файлу, который мне нужно изменить. что-то вроде c: \ folder1 \ file1.txt до d: \ folder2 \ file1.txt. tnks. Я дам вам знать результат.
огромная разница ... в половине случаев :) спасибо Ансгар.
ох ... и вы также были правы насчет $ srcPath и $ dstPath вне цикла ... моя ошибка. :)
[править - по словам Ансгара Вихерса, ускоритель PSCO доступен только с ps3 +.]
еще одна вещь, которая может помочь, - это заменить New-Object на [PSCustomObject]. это обычно несколько быстрее в использовании. что-то вроде этого ...
$DocObj = [PSCustomObject]$DocProperties
Другой способ использовать этот ускоритель типов - сделать то, что Ансгар Вичерс сделал в своем примере кода, но использовать ускоритель вместо командлета. нравится ...
[PSCustomObject]@{
'DOCNUM' = $Row.DOCNUM
'SOURCE' = $Row.DOCLOC
'DESTINATION' = $Row.DOCLOC -replace $srcPath, $dstPath
}
надеюсь, что это поможет,
Ли
спасибо за чаевые. Я попробую.
Возможно, стоит отметить, что ускоритель типа [PSCustomObject] недоступен до PowerShell v3.
Есть большая вероятность, что запрос SQL на самом деле выполняется только во время вызовов оператора if / foreach. Проверяли ли вы трассировку SQL, чтобы узнать, сколько времени занял фактический запрос SQL?