【问题标题】:Performance Enhancement in CSV value change though powershell通过 powershell 提高 CSV 值更改的性能
【发布时间】:2021-09-12 15:19:19
【问题描述】:

请参考前面的问题: How to get replace by id (Id value get from XML) and put into CSV, powershell

我需要添加 ForEach-Object 而不是 ForEach,我有 11,000 行。所以,这需要太多时间。

foreach ($csvRow in $csvRows) {
  foreach ($columnName in $columnNames) {
    $id = $csvRow.$columnName
    if (-not $id) { continue }
    $newId = @($xmlDoc.enum_types.enum_type.Where( { $_.field_name -eq $columnName }, 'First').
               items).ForEach( { $_.item }).Where( { $_.id -eq $id }).value
        $csvRow.$columnName = $newId
  }
}
$csvRows | Export-Csv -NoTypeInformation -Encoding utf8 $CSVpath

【问题讨论】:

  • 我很困惑。您想将当前的 foreach 更改为 Foreach-Object?为了速度表现? 1.) 你应该能够相当简单地改变它。 2.) 你会得到一个性能下降,将任何东西发送到管道中。慢 40 倍。
  • 您可能只想获取它并直接使用 SQL,这可能比 CSV 操作快得多。

标签: powershell csv


【解决方案1】:

您可以做的一件事是从其他问题中的“枚举”xml 预先计算您的查找。

原始代码 - 7649 毫秒

# setup

$xml = @"
<enum_types>
  <enum_type field_name="Test1">
    <items>
      <item>
        <id>1</id>
        <value>A</value>
      </item>
    </items>
  </enum_type>
  <enum_type field_name="Test2">
    <items>
      <item>
        <id>1</id>
        <value>A</value>
      </item>
    </items>
  </enum_type>
</enum_types>
"@;

$enums = [xml] $xml;

$csv = @("Test1, Test2");
$csv += 1..110000 | % { "1, 1" }

$data = $csv | ConvertFrom-Csv

$columnNames = @( "Test1", "Test2" );

# perf test - 7649 milliseconds
measure-command -expression {
    foreach ($csvRow in $data)
    {
        foreach ($columnName in $columnNames)
        {
            $id = $csvRow.$columnName
            if ( -not $id )
            {
                continue;
            }
            $newId = @($enums.enum_types.enum_type.Where( { $_.field_name -eq $columnName }, 'First').
                items).ForEach( { $_.item }).Where( { $_.id -eq $id }).value
            $csvRow.$columnName = $newId
        }
    }
}

使用预先计算的查找 - 792 毫秒

# setup 

... as above ...

# pre-compute lookups

$lookups = @{};
foreach( $enum_type in $enums.enum_types.enum_type )
{
    $lookups[$enum_type.field_name] = @{}
    foreach( $item in $enum_type.items.item )
    {
        $lookups[$enum_type.field_name][$item.id] = $item.value
    }
}
write-host ($lookups | convertto-json -depth 99)
# {
#   "Test1": {
#     "1": "A"
#   },
#   "Test2": {
#     "1": "A"
#   }
# }

# perf test - 792 milliseconds
measure-command -expression {
    foreach ($csvRow in $data)
    {
        foreach ($columnName in $columnNames)
        {
            $id = $csvRow.$columnName
            if (-not $id)
            {
                continue;
            }
            $csvRow.$columnName = $lookups[$columnName][$id]
        }
    }
}

您可能会从这种方法中挤出更多的东西,但它已经是 10 倍的加速(在我非常有限的基准测试中)。

【讨论】:

    【解决方案2】:

    将所有新项目预加载到hash tables

    $Types = $xmlDoc.enum_types.enum_type
    $HashTable = @{}
    
    Import-Csv .\1.Csv |ForEach-Object { $Names = $Null } {
        if (!$Names) {
            $Names = $_.psobject.Properties.Name
            foreach ($Name in $Names) {
                $HashTable[$Name] = @{}
                foreach ($Field in $Types.Where{$_.field_name -eq $Name}) {     
                    foreach ($Item in $Field.Items.Item) {
                        $HashTable[$Name][$Item.Id] = $Item.Value
                    }
                }
            }
        }
        foreach ($Name in $Names) {
            $id = $_.$Name
            If ($HashTable[$Name].Contains($Id)) {
                $_.$Name = $HashTable[$Name][$Id]
            }
        }
        $_
    } |Export-Csv .\1New.Csv -NoTypeInformation -Encoding utf8
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-08-18
      • 2017-01-28
      • 2023-03-22
      • 2014-11-25
      • 1970-01-01
      • 2011-05-18
      • 1970-01-01
      相关资源
      最近更新 更多