Ускорьте обработку из файла CSV

У меня есть проект, и я должен улучшить его производительность. У меня есть большая база данных Mysql, созданная из огромного файла CSV (100 миллионов строк). Время вставки не является проблемой, но время ответа на запрос очень важно, и иногда запрос с 2 соединениями занимает около 20 часов...

Чтобы сократить это время отклика, я попытался перенести свою базу данных на Cassandra, но безуспешно: моя модель данных не соответствует концепциям Cassandra. Тогда я хотел бы попробовать другой способ повысить производительность: Parallel Virutal File System. Вместо того, чтобы вставлять данные в базу данных Mysql и отправлять, а затем отправлять запрос, я попытался прочитать весь CSV-файл с многопоточностью и выполнил свои вычисления. Но результат был не очень хорошим: 2 м 20 с только для 1 000 000 строк.

На данный момент мои вычисления очень просты: в C++ с API-интерфейсом MPI-IO я просто подсчитываю количество значений пары различий из 2 столбцов. Для выполнения этих вычислений я использую хэш-карту, где каждый ключ представляет собой парное значение из CSV-файла. В конце я возвращаю размер хэш-карты. Вот небольшой код:

 MPI::Init(argc,argv); 
 cout << " INFO init done" << endl;
 int myrank = MPI::COMM_WORLD.Get_rank(); 
 int numprocs = MPI::COMM_WORLD.Get_size(); 
 get_filename(path_name, myrank);
 cout << " INFO open file : " << path_name << endl;
 MPI::File thefile = MPI::File::Open(MPI::COMM_WORLD, path_name.c_str(), 
                  MPI::MODE_RDONLY, 
                  MPI::INFO_NULL); 
 MPI::Offset offset = 101;
 MPI::Offset limit = thefile.Get_size();
 cout << " INFO go computing" << endl;
 do {
   thefile.Read_at(offset, buf, bufsize, MPI_CHAR, status);
   temp.assign(buf);
   Tokenize(temp,tokens,"\n");
   line.assign(tokens.at(0));
   tokens.clear();

   Tokenize(line,tokens,"\t");
   nidt_count(tokens);
   tokens.clear();
   offset += (line.size() + 1);
 }while(offset < limit);
 count = status.Get_count(MPI_INT);
 cout << "process " << myrank << " reads " << nidt_hash.size() << " nidt" << endl; 

Я работаю на сервере с 4 ядрами, 8 ГБ оперативной памяти. Мои данные находятся на NAS, смонтированном в NFS или Samba на моем сервере. Я мог бы добавить 2 или 3 сервера для обработки, но на данный момент я просто попробовал небольшой файл (1 миллион строк) на одном сервере, чтобы измерить производительность.

Наконец, мои вопросы:

  • Это хороший способ подумать о переходе на PVFS для моей проблемы? Я хотел бы сказать, что буду обрабатывать более сложный запрос, например: выбрать все строки с определенной датой (диапазон часов) и конкретным значением пары из определенных столбцов.
  • Знаете ли вы другие вещи, которые могли бы помочь мне улучшить обработку CSV-файла? Я думаю использовать Hadoop, Pytables или FasterCSV.

Вот образец моих данных, состоящий из 2 файлов csv:

Самый большой из них (100 миллионов строк) состоит из следующих элементов:

ID        DATE             NUM_1        NUM_2     NB_UNITE TYPUNIT CODE_1 CODE_2

0  2007-05-13 15:37:48  33671624244  33698802900    547      s       0      17
0  2007-05-13 15:52:22  33671624244  33672211799      5      s       0      17 
....

Второй более простой и небольшой (90 000), он похож на словарь, где из code_1 и code_2 я получаю значение с именем CODEVAL:

CODE_1 CODE_2 CODEVAL

  0       17     VS
  0       34     SS

Как вы и ожидали, обычно я создаю 2 таблицы по одной для каждого файла, и типичный запрос:

Select CODEVAL, hour(date) AS HEURE, COUNT(*) AS NBSMSSOR 
From Tables_1 Join CODEVAL using(CODE_1,CODE_2) 
Where CODEVAL='SS'

Извините за изложение, я не знаю, как сделать массив.


Вот образец моих данных, состоящий из 2 файлов csv:

  • самый большой из них (100 миллионов строк) состоит из следующих элементов:

    ID ДАТА NUM_1 NUM_2 NB_UNITE TYPUNIT CODE_1 CODE_2

    0 2007-05-13 15:37:48 33671624244 33698802900 547 s 0 17
    0 2007-05-13 15:52:22 33671624244 33672211799 5 s 0 17 ....

  • второй более простой и маленький (90 000), это как словарь, где из code_1 и code_2 я получаю значение с именем CODEVAL:

    CODE_1 CODE_2 CODEVAL

    0 17 VS

    0 34 SS

Как вы и ожидали, обычно я создаю 2 таблицы по одной для каждого файла, и типичный запрос:

  • Выберите CODEVAL, час(дата) AS HEURE, COUNT(*) AS NBSMSSOR Из Tables_1 Присоединитесь к CODEVAL, используя (CODE_1,CODE_2), где CODEVAL='SS'

Извините за изложение, я не знаю, как сделать массив.


person C. Oran    schedule 22.05.2011    source источник
comment
Пробовали ли вы анализировать и настраивать MySql: forge.mysql.com/wiki/Top10SQLPerformanceTips   -  person ChrisWue    schedule 23.05.2011
comment
Если вы не используете последнюю версию MySQL, подумайте об обновлении и прочитайте эту ссылку от @ChrisWue, это отличная вещь.   -  person Johan    schedule 23.05.2011
comment
Я был бы больше обеспокоен расположением ваших данных и тем, как вы получаете к ним доступ. Не могли бы вы вставить пример из 10 строк и самых распространенных запросов, которые вы используете?   -  person Karim Agha    schedule 23.05.2011
comment
Спасибо за вашу помощь, вы можете увидеть ниже пример моих данных, записанных в файле CSV. Я также пишу простой запрос.   -  person C. Oran    schedule 23.05.2011
comment
100 миллионов строк не очень похожи на большую базу данных, даже по стандартам MySQL.   -  person MSalters    schedule 23.05.2011


Ответы (3)


Мне кажется, что вы привязаны к вводу-выводу. Не помогает то, что ваши данные передаются по сети. Я подозреваю, что если вы просто добавите больше машин, ваша производительность упадет из-за дополнительных конфликтов. Помните, что по-прежнему есть только один шпиндель и только одна HD-головка, считывающая ваши данные. Для решения MPI я бы предложил сделать несколько копий данных и разместить их на самих серверах.

Что касается MySQL, я слышу, что вы говорите. Я обнаружил, что MySQL очень неэффективен с соединениями. Мне кажется, что он сканирует всю таблицу, хотя мог бы обойтись и без них. Я помню, как MySQL тратила больше минуты на запрос, а Oracle — меньше секунды. Может быть попробовать PostgreSQL? Я не уверен, что это лучше. Другой подход может заключаться в том, чтобы БД сортировала данные за вас, чтобы затем вы могли выполнить сканирование без хэш-карты.

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

person Adam    schedule 22.05.2011
comment
Спасибо за вашу помощь. Я подозревал, что я был связан вводом-выводом с головным диском... Но я надеялся, что мой NAS состоит из нескольких дисков в RAID 6, и я ожидаю от PVFS, что он сможет балансировать данные на разных дисках. диски из моего NAS, а затем распределить ввод-вывод по дискам. Я наверное ошибаюсь... - person C. Oran; 23.05.2011
comment
Ха-ха-ха, нет, я не скажу вам этого, извините. :) Второй самый медленный. Но у меня есть более сложный запрос, например: я хотел бы хранить в CSV-файле каждую строку в диапазоне одного часа и CODEVAL. В базе данных Mysql легко перевести мою потребность в запрос, но это занимает слишком много времени. Вот почему я попытался сделать это программно, как программа на C++ с MPI-IO, чтобы повысить производительность, но это выглядит более сложным в настройке... - person C. Oran; 23.05.2011

Если вы читаете данные из CSV, я предполагаю, что они не будут меняться слишком часто. Таким образом, вместо того, чтобы загружать его в общий продукт базы данных, вы также можете создать свой собственный индекс по данным CSV. Или вам нужна полная поддержка SQL?

Кроме того, вы упоминаете, что хотите вернуть ЧИСЛО разных K, V-пар. Однако вы действительно вычисляете фактические пары. Я не знаю, нужны ли они вам для какой-то другой цели, но вы также можете получить это число как #distinctKeys x #distinctValues ​​без фактического создания HashMap.

Предполагая, что вы создаете индекс для каждого столбца формы

value -> {r | r is a byteOffset of a row that has "value" in the index column}

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

Я надеюсь, что этот ответ будет полезен, так как я не уверен, какие другие требования должны быть выполнены. Это решение значительно менее мощное, чем БД, поддерживающая SQL (особенно вставки сделают вещи намного сложнее), но, по крайней мере, определение количества различных пар должно быть быстрее на несколько порядков.

person b.buchhold    schedule 23.05.2011

Разделяй и властвуй Сотня небольших баз данных должна работать НАМНОГО быстрее. вы сами решаете, как его разбить - используйте split() или slice(). В настоящее время я использую первый символ первого слова каждой строки, поэтому там, где когда-то была одна огромная медленная БД, теперь есть (A - Z + a - z + 0 - 9) 62 небольшие более быстрые базы данных. Еще одно преимущество заключается в том, что теперь ноутбук может выполнять работу, которую раньше мог выполнять только мощный и дорогой ПК.

person Edward    schedule 02.03.2015