Wie sortiere ich große Dateien?

35

Ich habe einen PC mit Intel (R) Pentium (R) -CPU G640 bei 2,80 GHz und 8 GB RAM. Ich führe darauf Scientific Linux 6.5 mit EXT3-Dateisystem aus.

Wie kann ich in diesem Setup sort -ueine 200-Gigabyte-Datei am schnellsten bearbeiten?

Soll ich die Datei in kleinere Dateien (kleiner als 8 GB) sort -uaufteilen, sie zusammenfügen und dann wieder in eine andere Größe aufteilen sort -uusw.? Oder gibt es Sortierskripte, Programme, die mit meiner begrenzten RAM-Größe so große Dateien verarbeiten können?

evachristine
quelle
6
Bitte bearbeiten Sie Ihre Frage und erklären Sie, was passiert, wenn Sie den von Ihnen geposteten Befehl ausführen. Haben Sie keinen Speicherplatz mehr? Der Befehl sollte funktionieren, solange Sie über genügend freien Speicherplatz verfügen /tmp.
Terdon
1
Die gewählte Antwort sagt im Wesentlichen, was @terdon sagt, aber sehen Sie sich auch diese an - stackoverflow.com/a/13025731/2801913 . Sie werden GNU paralleldafür brauchen, denke ich, und nicht die moreutils parallel, die auf einigen Systemen standardmäßig installiert sind.
Graeme
1
Sie können die Datei auf Amazon S3 hochladen und dann einen Elastic Map Reduce-Job mit ein paar hundert Knoten starten, um sie zu sortieren!
Alan Shutko
2
sort(1)könnte keinen Platz mehr haben /tmp; In diesem TMPDIR-T=<tmpdir>
Fall

Antworten:

46

GNU sort(dies ist die Standardeinstellung auf den meisten Linux-Systemen) hat eine --parallelOption. Von http://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html :

'--parallel = n'

Stellen Sie die Anzahl der parallel laufenden Sortierungen auf n ein. Standardmäßig ist n auf die Anzahl der verfügbaren Prozessoren festgelegt, jedoch auf 8 begrenzt, da sich die Leistung danach verschlechtert. Beachten Sie auch, dass die Verwendung von n Threads die Speichernutzung um den Faktor log n erhöht. Siehe auch nproc-Aufruf.

Da Ihre CPU 2 Kerne hat, können Sie Folgendes tun:

sort --parallel=2 -uo list-sorted.txt list.txt

Es ist besser, die tatsächliche Anzahl der Kerne anzugeben, da aufgrund des Prozessors mit Hyper-Threading möglicherweise mehr Kerne vorhanden sind .

Sie können auch experimentieren nice, um die Priorität der Prozessorplanung und ionicedie E / A-Planung zu beeinflussen. Sie können die Priorität gegenüber anderen Prozessen wie diesem erhöhen. Ich glaube nicht, dass dies zu erheblichen Einsparungen führt, da diese normalerweise besser sind, um sicherzustellen, dass ein Hintergrundprozess nicht zu viele Ressourcen verbraucht. Trotzdem können Sie sie mit etwas wie kombinieren:

nice -n -20 ionice -c2 -n7 sort --parallel=2 -uo list-sorted.txt list.txt

Wie Gilles bemerkte, ist die Verwendung eines einzelnen GNU-Sortierbefehls schneller als jede andere Methode zum Auflösen der Sortierung, da der Algorithmus bereits für die Verarbeitung großer Dateien optimiert ist. Alles andere wird wahrscheinlich nur die Dinge verlangsamen.

Graeme
quelle
10
Und Sie sollten beachten, dass ein sortdirekter Anruf besser ist als alles andere, was Sie tun können. GNU sort ist so konzipiert, dass es mit Dateien, die viel größer als RAM sind, gut zurechtkommt.
Gilles 'SO - hör auf böse zu sein'
Die Option --parallel sort funktioniert auf meinen RH6.5-Servern nicht. Sort --version glaubt, dass es aus coreutils 8.4 stammt. Welche Version brauche ich zur Parallelversion?
markus_b
3
Siehe auch superuser.com/questions/938558/sort-parallel-isnt-parallelizing - Sie müssen so etwas wie -S512M angeben können , wenn Sie es bemerken ist eigentlich nicht parallelisiert.
Unhammer
46

Die Verwendung des sortBefehls ist wahrscheinlich die schnellste Option.

Aber Sie werden wahrscheinlich das Gebietsschema auf C festlegen wollen.

sort -umeldet keine eindeutigen Zeilen, sondern eine von jedem Satz von Zeilen, die gleich sortiert sind. Im C-Gebietsschema müssen 2 verschiedene Zeilen nicht unbedingt gleich sortiert sein, aber das ist in den meisten UTF-8-basierten Gebietsschemata auf GNU-Systemen nicht der Fall.

Durch die Verwendung des Gebietsschemas C wird außerdem vermieden, dass UTF-8 analysiert und komplexe Sortierreihenfolgen verarbeitet werden müssen, wodurch die Leistung erheblich verbessert wird.

So:

LC_ALL=C sort -u file

Sie können die Leistung auch verbessern, indem Sie ein schnelleres Laufwerk (oder ein anderes Laufwerk als das, auf dem sich die Eingabe- und / oder Ausgabedateien befinden) für die temporären Dateien (mit -Toder $TMPDIRUmgebungsvariable) verwenden oder -Sdie von einigen sortImplementierungen unterstützte Option ausprobieren. .

Bei bestimmten Eingaben oder bei langsamer Speicherung kann die Verwendung der --compress-programGNU-Option sort(z. B. mit lzop) zusätzlich zur Speichernutzung die Leistung verbessern.


Nur ein Hinweis für diejenigen, die (zu Recht) beanstanden, dass es nicht die richtige Reihenfolge sein wird :

Ich stimme zu, dass ich als Mensch gerne sehen würde, wie Stéphane zwischen Stefan und Stephanie sortiert , aber:

  • Ein Computer möchte, dass Stéphane danach sortiert é(zumindest wenn er als U + 00E9 ausgedrückt wird), als Zeichen oder nach den Bytes seiner UTF-8-Codierung (in Bezug auf Codepunkt oder Bytewert). Dies ist eine Sortierreihenfolge, die sehr einfach zu implementieren ist, eine strikte Gesamtreihenfolge darstellt und keine Überraschung darstellt.
  • Die Sortierreihenfolge Ihres Gebietsschemas ist wahrscheinlich in vielen Fällen auch für einen Menschen nicht zufriedenstellend. Zum Beispiel auf meinem System mit dem Standardgebietsschema en_GB.utf8:

    • Stéphane und Stéphane (einer mit U + 00E9, der andere mit eU + 0301) sortieren nicht gleich:

      $ printf '%b\n' 'Ste\u0301phane' 'St\u00e9phane' | sort -u
      Stéphane
      Stéphane
      
    • aber ③, ①, ② alle sortieren gleich (offensichtlich ein Fehler in diesen Gebietsschemadefinitionen):

      $ printf '%s\n' ③ ① ② | sort -u
      ③
      

      Hier ist es ③, aber es hätte genauso gut ① oder ② sein können

Also IMO, die Chancen stehen gut, dass Sie sort -umit LC_ALL = C immer wollen , wenn Sie eindeutige Zeilen wollen. Und wenn Sie möchten, dass die resultierende Liste in der Sortierreihenfolge des Benutzers sortiert wird, leiten Sie sie sorterneut an:

LC_ALL=C sort -u | sort

LC_ALL=C sort | LC_ALL=C uniq -c | sort -k2
Stéphane Chazelas
quelle
8
+1 für das Setzen des Gebietsschemas: Es kann eine enorme Auswirkung auf die Leistung haben
Adrian Pronk
1
Ja. Sortierdatei mit 250000 Zeilen der LC_ALL beschleunigt die Dinge 8-mal.
Jan Vlcinsky
-1

Hier ist ein fertiges Bash-Skript zum Sortieren von TB-Skalendaten auf einem normalen Computer mit ein paar GB RAM: http://sgolconda.blogspot.com/2015/11/sort-very-large-dataset.html Überprüft die Anzahl von Kerne deine Maschine wie und benutze alle Kerne. Kann numerische oder String-Dateien sortieren. Kann verwendet werden, um eindeutige Datensätze in TB-Skalendaten zu finden.

user213743
quelle
Dies ist kein guter Vorschlag. Das Skript ist immens aufgebläht und teilt die Eingabedatei, um die Teile zu sortieren, auf die die akzeptierte Antwort hinweist, dass sie mit GNU sort nicht benötigt werden.
Thorbjørn Ravn Andersen