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

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

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

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

 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.

Вот пример моих данных, составленный из файла 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'

Извините за презентацию, я не знаю, как сделать массив.


Вот пример моих данных, составленный из файла csv:

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

    ИД ДАТА 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 с 0 17....

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

    CODE_1 CODE_2 CODEVAL

    0 17 VS

    0 34 SS

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

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

Извините за презентацию, я не знаю, как сделать массив.

Ответ 1

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

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

Если ваши записи не являются ginormous, записи 100M не должны быть такими плохими.

Ответ 2

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

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

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

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

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

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

Ответ 3

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