Более быстрая итерация

У меня есть этот код, который является частью функции, которая возвращает список строк 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

Есть большая вероятность, что запрос SQL на самом деле выполняется только во время вызовов оператора if / foreach. Проверяли ли вы трассировку SQL, чтобы узнать, сколько времени занял фактический запрос SQL?

Russell 08.10.2018 00:51

@Russell запрос занимает максимум 10 секунд ... Я уже отладил код, и это занимает около 5 минут в foreach. спасибо

Nuno 08.10.2018 00:55

круто - еще одна вещь, которую нужно проверить, - это попытаться удалить 2 строки с сопоставлением регулярных выражений, чтобы они не вызывали задержку.

Russell 08.10.2018 00:58

@Russell Я уже думал об этом, но мне нужно это изменение. Еще попробую удалить, чтобы увидеть результат.

Nuno 08.10.2018 01:05

Ну ... особой разницы. Собственно вроде точно так же :(

Nuno 08.10.2018 01:13

Это выглядит пугающе уязвимым для атак с использованием sql-инъекций.

Joel Coehoorn 08.10.2018 01:25

@JoelCoehoorn, ты абсолютно прав. Я поменяю позже. Просто тестирую tnks

Nuno 08.10.2018 01:26

Никогда не тестировал. Но мне интересно, быстрее ли пересылка $ SqlDocmasterTableResuls.Rows в foreach. Сделайте первую строчку $row = $_

Robert Cotterman 08.10.2018 06:42

Слишком часто «поменяй потом» превращайся «никогда не меняй».

Joel Coehoorn 08.10.2018 20:13
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
За пределами сигналов Angular: Сигналы и пользовательские стратегии рендеринга
TL;DR: Angular Signals может облегчить отслеживание всех выражений в представлении (Component или EmbeddedView) и планирование пользовательских...
Sniper-CSS, избегайте неиспользуемых стилей
Sniper-CSS, избегайте неиспользуемых стилей
Это краткое руководство, в котором я хочу поделиться тем, как я перешел от 212 кБ CSS к 32,1 кБ (сокращение кода на 84,91%), по-прежнему используя...
0
9
53
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Избегайте добавления к массиву в цикле. Лучший способ записать данные цикла в переменную - просто собрать выходные данные цикла в переменной:

$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. Я дам вам знать результат.

Nuno 08.10.2018 01:24

огромная разница ... в половине случаев :) спасибо Ансгар.

Nuno 08.10.2018 01:36

ох ... и вы также были правы насчет $ srcPath и $ dstPath вне цикла ... моя ошибка. :)

Nuno 08.10.2018 02:04

[править - по словам Ансгара Вихерса, ускоритель PSCO доступен только с ps3 +.]

еще одна вещь, которая может помочь, - это заменить New-Object на [PSCustomObject]. это обычно несколько быстрее в использовании. что-то вроде этого ...

$DocObj = [PSCustomObject]$DocProperties

Другой способ использовать этот ускоритель типов - сделать то, что Ансгар Вичерс сделал в своем примере кода, но использовать ускоритель вместо командлета. нравится ...

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

надеюсь, что это поможет,
Ли

спасибо за чаевые. Я попробую.

Nuno 08.10.2018 02:04

Возможно, стоит отметить, что ускоритель типа [PSCustomObject] недоступен до PowerShell v3.

Ansgar Wiechers 08.10.2018 09:24

Другие вопросы по теме