Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

大容量ファイルのソート時のメモリ不足の回避

解決したいこと

大容量ファイルソート時のメモリ不足

power shellで複数CSVをソートし、重複しているレコードのリストを作成する
プログラムを作成しています。
sort-objectでソートを行う際に、メモリ使用量がほぼ100%となり
最終的にマシンにログインができなくなってしまっている状況です。
(ログイン⇒画面ブラックアウト⇒ログイン画面に戻る)←メモリ不足が原因?

使用するメモリの上限を設定する方法
(足りない部分は自動的にディスク上に一時ファイルを作成し、処理してくれるという認識)。
または、その他解決方法があればご教授いただきたいです。

環境

プロセッサ:Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz 3.00 GHz
メモリ:24GB
処理ファイル:最大サイズ4GBで計12GBほど(5つのcsvファイル)←将来的には最大10GB

発生している問題・エラー

sort-objectでソート時にメモリ使用量がほぼ100%になりマシン動作に影響を及ぼしている

該当するソースコード

#csvファイルデータの並び替え
$sorts = Get-Content *.csv | Sort-Object

#前レコードのデータ保持用変数
$name = ""
$postal_code= ""
$birthdate= ""

#出力用配列の制御用
$OutputArray = New-Object System.Collections.ArrayList
$loop_count = 0

foreach ($sort in $sorts)
{
  $array = $sort.Split(",")
    #前レコードの比較し、同じデータだった場合、重複リストに出力
    IF(($name -eq $array[23]) -and ($birthdate =  $array[22]) -and ($postal_code =  $array[26])){
    
        $ary=@( $array[0], $array[23],$array[22],$array[26])
        $ary -join ',' | Out-File -FilePath "C:\Users\user\Desktop\test\output.txt" -Append -Encoding unicode
        Write-Host "重複"
    }

   #全レコード比較用
   $name =  $array[23]
   $postal_code = $array[26]
   $birthdate = $array[22]
   
   #総件数確認のためカウントアップ
   $loop_count++
}

#最終的にここで出力ファイルの重複を削除←←←未実装

自分で試したこと

ファイルを分割しての処理
Linuxの buffer-sizeや-sのような使用するメモリ上限の変更がないかの調査

0

2Answer

Windowsのsortコマンド(C:\Windows\System32\sort.exe)や、
wsl(Ubuntu)でsortコマンドによるソートを実行してみたらどうでしょうか?

0Like

全然詳しくないのですが、PowerShellのパイプって渡されたストリーム全部をオンメモリで処理しませんか?以前 Invoke-WebRequest でUbuntuを取ってきてパイプで wsl.exe コマンドに渡したらメモリがあふれた記憶があります。

その時は、PowerShellから cmd.exe を呼び出してその中でcurl.exe,wls.exeのパイプ処理を行いました。

そこから想像するに

$sorts = Get-Content *.csv | Sort-Object

この処理だと

  1. *.csvを全て連結した巨大なファイルをパイプを通したところでメモリにストックしている。更にそこで文字コード変換?オブジェクト変換?等が行われる
  2. Sort-Objectがオンメモリで処理している?
  3. $sorts に代入するとメモリにソート後テキスト(?テキストをデータとして持つオブジェクト?)が展開される

この3ヶ所が大量にメモリを消費しそうな感じがします。

試してみるべきは

  1. Get-Content *.csv ではなく結合した中間ファイルを作る
  2. 大量ソートを行うフリーソフトを試してみる。後述のURLにCMSortというのが紹介されていました。
  3. ソート後のテキストを変数に持つのではなく、これもファイルへ書き出してファイル操作としてその後の処理を行う

参考URLの中にはLinuxを使えとか、MySQLに一旦入れて操作しろという意見も出てくると思いますがこのあたりの方法が妥当な気がします。

参考)
https://superuser.com/questions/1300361/sort-the-contents-of-an-extremely-large-800gb-text-file-on-windows

0Like

Your answer might help someone💌