2012-01-17 17 views
6

Mam potrzebę przeanalizowania dużego pliku rozdzielanego potokami w celu policzenia liczby rekordów, których kolumna 5. spełnia i nie spełnia moich kryteriów.Potrzebujesz pomocy w poprawieniu wydajności skryptu analizującego tekst rozdzielany za pomocą PowerShell

PS C:\temp> gc .\items.txt -readcount 1000 | ` 
    ? { $_ -notlike "HEAD" } | ` 
    % { foreach ($s in $_) { $s.split("|")[4] } } | ` 
    group -property {$_ -ge 256} -noelement | ` 
    ft –autosize 

Polecenie to robi to, co chcę, wracając wyjście tak:

 
    Count Name 
    ----- ---- 
1129339 True 
2013703 False 

Jednak dla pliku testowego 500 MB, to polecenie trwa około 5,5 minuty, aby uruchomić mierzona Measure-Command. Typowy plik ma ponad 2 GB, a oczekiwanie na ponad 20 minut jest niepożądanie długie.

Czy widzisz sposób na poprawę wydajności tego polecenia?

Na przykład, czy istnieje sposób na określenie optymalnej wartości dla ReadCount w Get-Content? Bez tego ukończenie tego samego pliku zajmuje 8,8 minuty.

+0

Czy próbowałeś StreamReader? Myślę, że Get-Content ładuje cały plik do pamięci, zanim zrobi coś z nim. – Gisli

+0

Masz na myśli importując System.IO? – neontapir

+0

Tak, użyj struktury .net, jeśli możesz. Kiedyś czytałem duże pliki dziennika, które SQL Server generuje z dobrymi wynikami. Nie znam żadnego innego sposobu, by wydajnie czytać duże pliki, ale nie jestem ekspertem. – Gisli

Odpowiedz

4

Czy próbowałeś StreamReader? Myślę, że Get-Content ładuje cały plik do pamięci, zanim zrobi coś z nim.

StreamReader class

4

Korzystanie @ nutą Gisli za, oto skrypt skończyło się z:

param($file = $(Read-Host -prompt "File")) 
$fullName = (Get-Item "$file").FullName 
$sr = New-Object System.IO.StreamReader("$fullName") 
$trueCount = 0; 
$falseCount = 0; 
while (($line = $sr.ReadLine()) -ne $null) { 
     if ($line -like 'HEAD|') { continue } 
     if ($line.split("|")[4] -ge 256) { 
      $trueCount++ 
     } 
     else { 
      $falseCount++ 
     } 
} 
$sr.Dispose() 
write "True count: $trueCount" 
write "False count: $falseCount" 

daje ona takie same wyniki w około minutę, która spełnia moje wymagania eksploatacyjne.

2

Wystarczy dodać kolejny przykład przy użyciu StreamReader, aby odczytać bardzo duży plik dziennika IIS i wyświetlając wszystkie unikalne adresy IP klientów i niektóre dane perf.

$path = 'A_245MB_IIS_Log_File.txt' 
$r = [IO.File]::OpenText($path) 

$clients = @{} 

while ($r.Peek() -ge 0) { 
    $line = $r.ReadLine() 

    # String processing here... 
    if (-not $line.StartsWith('#')) { 
     $split = $line.Split() 
     $client = $split[-5] 
     if (-not $clients.ContainsKey($client)){ 
      $clients.Add($client, $null) 
     } 
    } 
} 

$r.Dispose() 
$clients.Keys | Sort 

Nieco porównanie wydajności na Get-Content:

StreamReader: zakończone: 5,5 sekund PowerShell.exe: 35328 MB RAM.

Get-Content: Zakończone: 23,6 sekundy. PowerShell.exe: 1,110,524 KB pamięci RAM.

Powiązane problemy