Ускорить обработку из файла CSV - PullRequest
10 голосов
/ 22 мая 2011

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

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

На данный момент мои вычисления очень просты: в C ++ с API-интерфейсом MPI-IO я просто подсчитываю число парных разностей в двух столбцах. Для выполнения этих вычислений я использую хэш-карту, где каждый ключ является парным значением из файла 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.

Вот пример моих данных, составленный из 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 с 0 17
    0 2007-05-13 15:52:22 33671624244 33672211799 5 с 0 17 ....

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

    CODE_1 CODE_2 CODEVAL

    0 17 VS

    0 34 СС

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

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

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

Ответы [ 3 ]

2 голосов
/ 23 мая 2011

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

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

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

0 голосов
/ 03 марта 2015

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

0 голосов
/ 23 мая 2011

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

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

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

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

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

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

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