sqlite — обработка больших объемов данных в C ++, нужен подход

Итак, у меня есть файл размером 1 ГБ в формате CSV, например, который я преобразовал в базу данных SQLite3

column1;column2;column3
1212;abcd;20090909
1543;efgh;20120120

За исключением того, что у меня 12 столбцов. Теперь мне нужно прочитать и отсортировать эти данные и переформатировать их для вывода, но когда я пытаюсь это сделать, мне кажется, что у меня заканчивается ОЗУ (с использованием векторов). Я читаю его из SQLite и сохраняю каждую строку файла в структуре, которая затем передается обратно в deque. Как я уже сказал, у меня заканчивается память, когда использование оперативной памяти приближается к 2 ГБ, и приложение вылетает. Я попытался использовать STXXL, но, по-видимому, он не поддерживает векторы не POD-типов (поэтому это должны быть long int, double, char и т. Д.), И мой вектор состоит в основном из std :: string, некоторого boost :: date и одного double значение.

По сути, мне нужно сгруппировать все «строки» вместе, имеющие одинаковое значение в определенном столбце, другими словами, мне нужно отсортировать данные по одному столбцу, а затем работать с этим.

Любой подход к тому, как я могу читать во всем или, по крайней мере, сортировать это? Я бы сделал это с SQLite3, но это кажется трудоемким. Возможно я не прав.

Благодарю.

0

Решение

В порядке желательности:

  1. вообще не используйте C ++, просто используйте Сортировать если возможно
  2. если вы привыкли использовать БД для обработки не очень большого CSV-файла, что звучит как не совсем реляционный способ, перенесите всю тяжелую работу на БД и позвольте ей беспокоиться об управлении памятью.
  3. если вы должны сделать это в C ++:
    • полностью пропустите шаг SQLite3, поскольку вы его ни для чего не используете. Просто отобразите файл CSV в память и создайте вектор указателей строк. Сортировать этот без перемещения данных
    • если вы должны разобрать строки в структуры:
      • не храните строковые столбцы как std::string — это требует дополнительного несмежного выделения, которое приведет к потере памяти. Предпочитаю встроенный массив символов, если длина ограничена
      • выберите наименьший целочисленный размер, который будет соответствовать вашим значениям (например, uint16_t будет соответствовать вашим значениям первого столбца образца)
      • будьте осторожны с заполнением: проверьте размер вашей структуры и измените порядок членов или упакуйте ее, если она намного больше ожидаемой
1

Другие решения

Если вы хотите придерживаться подхода SQLite3, я рекомендую использовать список вместо вектора, чтобы вашей операционной системе не приходилось находить 1 ГБ или более непрерывной памяти.

Если вы можете пропустить шаг SQLite3, вот как я бы решил эту проблему:

  1. Написать класс (например, MyRow), который имеет поле для каждого столбца в вашем наборе данных.
  2. Прочитайте файл в std::list<MyRow> где каждая строка в вашем наборе данных становится экземпляром MyRow
  3. Напишите предикат, который сравнивает желаемый столбец
  4. Используйте функцию сортировки std :: list для сортировки ваших данных.

Я надеюсь, это поможет вам.

1

Существуют значительные накладные расходы для std::string, Если твой struct содержит std::string для каждого столбца вы будете тратить много места на char * указатели, malloc заголовки и т. д.

Попробуйте разобрать все числовые поля сразу при чтении файла и сохранить их в своей структуре как ints или что вам нужно.

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

0

Создайте структуру для ваших записей.

Запись должна иметь функции «упорядочивания» для полей, по которым нужно отсортировать.

Считайте файл как объекты и сохраните его в контейнере с возможностью произвольного доступа, например std::vector или же std::array,

Для каждого поля вы хотите отсортировать по:
Создать таблицу индексов, std::mapиспользуя значение поля в качестве ключа и индекс записи в качестве значения.

Чтобы обработать поля по порядку, выберите свою таблицу индексов и выполните итерации по таблице индексов. Используйте поле значения (a.k.a. index), чтобы извлечь объект из контейнера объектов.

Если записи имеют фиксированную длину или могут быть преобразованы в фиксированную длину, вы можете записать объекты в двоичном виде в файл и поместить файл в разные записи. Используйте таблицу индексов, как указано выше, за исключением использования позиций файла вместо индексов.

0

Спасибо за ваши ответы, но я разобрался с очень быстрым и простым подходом.

Я позволил SQLite3 сделать эту работу за меня, задав ему следующий запрос:

SELECT * FROM my_table ORDER BY key_column ASC

Для файла размером 800 МБ это заняло около 70 секунд, а затем я получил все данные в моей программе на C ++, уже упорядоченные по столбцу, по которому я хотел их сгруппировать, и обработал столбец по одной группе за раз и вывел их по одному в желаемом формате вывода, сохраняя мою оперативную память свободной от перегрузки. Общее время операции около 200 секунд, что меня вполне устраивает.

Спасибо за ваше время.

0
По вопросам рекламы [email protected]