Как сортировать большие файлы?

35

У меня есть ПК с процессором Intel® Pentium® G640 с тактовой частотой 2,80 ГГц и 8 ГБ оперативной памяти. Я использую Scientific Linux 6.5 на нем с файловой системой EXT3.

На этой установке, какой самый быстрый способ я могу сделать sort -uна 200-гигабайтном файле?

Должен ли я разделить файл на более мелкие файлы (размером менее 8 ГБ), sort -uобъединить их, затем снова разделить на другой размер, sort -uснова и т. Д.? Или есть какие-нибудь сценарии сортировки, программы, которые могут обрабатывать файлы с таким большим объемом памяти?

evachristine
источник
6
Пожалуйста, отредактируйте свой вопрос и объясните, что происходит, когда вы пытаетесь опубликовать команду Вам не хватает места на диске? Команда должна работать до тех пор, пока у вас достаточно свободного места /tmp.
Terdon
1
Выбранный ответ в основном говорит о том, что говорит @terdon, но также проверьте этот - stackoverflow.com/a/13025731/2801913 . parallelЯ думаю, что для этого вам понадобится GNU, а не moreutils parallel, установленный по умолчанию в некоторых системах.
Грэм
1
Вы можете загрузить файл в Amazon S3, а затем раскрутить задание Elastic Map Reduce с несколькими сотнями узлов, чтобы отсортировать его!
Алан Шутко
2
sort(1)может не хватить места на /tmp; если это так, вы можете назначить другую область для временных файлов с помощью переменной среды TMPDIRили флага-T=<tmpdir>
vonbrand

Ответы:

46

GNU sort(который используется по умолчанию в большинстве систем Linux), имеет --parallelопцию. С http://www.gnu.org/software/coreutils/manual/html_node/sort-invocation.html :

'--Parallel = п'

Установите количество сортировок, запущенных параллельно, на n. По умолчанию для n установлено число доступных процессоров, но оно не должно превышать 8, поскольку после этого наблюдается снижение производительности. Также обратите внимание, что использование n потоков увеличивает использование памяти в log n. Также смотрите вызов nproc.

Поскольку ваш процессор имеет 2 ядра, вы можете сделать:

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

Лучше указать фактическое количество ядер, так как может показаться, что их больше из-за того, что процессор имеет гиперпоточность .

Вы также можете поэкспериментировать с niceвлиянием приоритета планирования процессора и планированием ioniceввода / вывода. Вы можете увеличить приоритет над другими процессами, подобными этим, я не думаю, что это даст вам большую экономию, поскольку они обычно лучше для обеспечения того, чтобы фоновый процесс не использовал слишком много ресурсов. Тем не менее, вы можете объединить их с чем-то вроде:

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

Также обратите внимание, что, как прокомментировал Жиль , использование одной команды сортировки GNU будет быстрее, чем любой другой метод разрушения сортировки, поскольку алгоритм уже оптимизирован для обработки больших файлов. Все остальное, скорее всего, только замедлит ход событий.

Graeme
источник
10
И вы должны заметить, что звонить sortнапрямую лучше, чем что-либо еще, что вы могли бы сделать. Сортировка GNU разработана для того, чтобы хорошо справляться с файлами, которые намного больше, чем RAM.
Жиль "ТАК - перестань быть злым"
Опция сортировки --parallel не работает на моих серверах RH6.5. Sort --version считает, что это происходит из coreutils 8.4. Какая версия мне нужна для параллельной версии?
markus_b
3
См. Также superuser.com/questions/938558/sort-parallel-isnt-parallelizing - вам может потребоваться указать что-то вроде -S512M, если вы заметите, что на самом деле это не распараллеливание.
unhammer
46

Использование sortкоманды, вероятно, будет самым быстрым вариантом.

Но вы, вероятно, захотите исправить локаль до C.

sort -uне сообщает об уникальных строках, но об одном наборе строк, которые сортируются одинаково. В языковом стандарте C две разные строки обязательно не сортируются одинаково, но это не так в большинстве языковых стандартов на основе UTF-8 в системах GNU.

Кроме того, использование языкового стандарта C позволяет избежать дополнительных затрат на анализ UTF-8 и обработку сложных порядков сортировки, что значительно повышает производительность.

Так:

LC_ALL=C sort -u file

Вы также можете повысить производительность, используя более быстрый диск (или диск, отличающийся от того, на котором находятся входные и / или выходные файлы) для временных файлов (используя переменную среды -Tили $TMPDIRпеременную среды), или переключившись на -Sпараметр, поддерживаемый некоторыми sortреализациями) ,

Для некоторого типа ввода или для медленного хранения использование --compress-programопции GNU sort(например, с lzop) может улучшить производительность в дополнение к использованию хранилища.


Теперь просто отметим для тех, кто возражает (справедливо в некоторой степени), что это будет неправильный порядок :

Я согласен, что как человек, я хотел бы видеть Стефана между Стефаном и Стефани , но:

  • Компьютер хотел бы Stephane к своего рода после того, как так é(по крайней мере , когда выражается в виде U + 00E9) в качестве символа или байтов его UTF-8 кодировкой сортов после (с точки зрения стоимости или элемент кода байта). Это порядок сортировки, который очень прост в реализации, является строгим общим порядком и не вызывает удивления.
  • Порядок сортировки вашей локали, вероятно, не будет удовлетворительным во многих случаях даже для человека. Например, в моей системе со стандартным языком en_GB.utf8:

    • Стефан и Стефан (один с U + 00E9, другой с eU + 0301) не сортируют одно и то же:

      $ printf '%b\n' 'Ste\u0301phane' 'St\u00e9phane' | sort -u
      Stéphane
      Stéphane
      
    • но ③, ①, ② все сортируются одинаково (очевидно, ошибка в этих определениях локали):

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

      Вот, это but, но с таким же успехом это могло быть ① или ②

Итак, IMO, скорее всего, вы всегда хотите sort -uс LC_ALL = C, если вы хотите уникальные строки. И если вы хотите, чтобы этот результирующий список был отсортирован в порядке сортировки пользователя, передайте его sortснова:

LC_ALL=C sort -u | sort

LC_ALL=C sort | LC_ALL=C uniq -c | sort -k2
Стефан Шазелас
источник
8
+1 за настройку локали: это может оказать огромное влияние на производительность
Adrian Pronk
1
Да. Сортировка файла с 250000 строками LC_ALL ускоряет работу в 8 раз.
Ян Влчинский
-1

Вот готовый скрипт bash для сортировки данных в масштабе ТБ на обычном компьютере с парой оперативной памяти в ГБ: http://sgolconda.blogspot.com/2015/11/sort-very-large-dataset.html Проверяет количество Ядро вашей машины как и использует все ядра. Можно сортировать, числовые или строковые файлы. Может использоваться для поиска уникальных записей в данных шкалы ТБ.

user213743
источник
Это не очень хорошее предложение. Скрипт очень раздут и разбивает входной файл для сортировки частей, которые, как указывает принятый ответ, не нужны для сортировки GNU.
Турбьерн Равн Андерсен