Лучший дизайн для сценария - PullRequest
1 голос
/ 18 мая 2009

У меня есть требование, когда мне нужно выбрать около 60 миллионов записей из базы данных. После того, как у меня есть все записи в ResultSet, я должен сформировать некоторые столбцы в соответствии с требованиями клиента (формат даты и числовой формат), а затем мне нужно записать все записи в файл (вторичная память).

  • В настоящее время я выбираю записи по дням (7 выборок за 7 дней) из БД и помещаю их в HashMap. Чтение из HashMap и форматирование некоторых столбцов и, наконец, запись в файл (отдельный файл в течение 7 дней).
  • Наконец, я объединяю все 7 файлов в один файл.

  • Но весь этот процесс занимает 6 часов. Чтобы улучшить этот процесс, я создал 7 потоков за 7 дней, и все темы пишут отдельные файлы.

  • Наконец, я объединяю все 7 файлов в один файл. Этот процесс занимает 2 часа. Но моя программа отправляется в OutOfMemory через 1 час и т. Д.

Пожалуйста, предложите лучший дизайн для этого сценария, должен ли я использовать какой-то механизм кэширования, если да, то какой и как?

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

Ответы [ 4 ]

4 голосов
/ 18 мая 2009

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

В зависимости от вашей базы данных БД у них могут быть такие инструменты, как SSIS для Sql Server 2005+.

Редактировать

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

ADO.Net имеет DataReader, который является только перенаправленным, только для чтения (Firehose) курсором набора результатов. Он возвращает данные во время выполнения запроса. Это очень важно. По сути, моя логика будет:

IDataReader reader=GetTheDataReader(dayOfWeek);

while (reader.Read())
{
    file.Write(formatRow(reader));
}

Поскольку это выполняется, когда мы возвращаем строки, вы не собираетесь блокировать доступ к сети, что, я полагаю, является для вас огромным узким местом. Ключевым моментом здесь является то, что мы долго не храним ничего в памяти, поскольку мы циклически повторяем, читатель отбрасывает результаты, а файл записывает строку на диск.

2 голосов
/ 18 мая 2009

Я думаю, Джош предлагает следующее:

У вас есть циклы, в которых вы в настоящее время просматриваете все записи результатов вашего запроса (просто используя здесь псевдокод):

while (rec = getNextRec() )
   {
   put in hash ...
   }

for each rec in (hash)
   {
   format and save back in hash ...
   }

for each rec in (hash)
   {
   write to a file ...
   }

instead, do it like this:

while (rec = getNextRec() )
   {
   format fields ...
   write to the file ...
   }

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

1 голос
/ 18 мая 2009

Очевидно, что чтение 60 миллионов записей одновременно занимает всю вашу память - так что вы не можете этого сделать. (т.е. ваша 7-ниточная модель). Чтение 60 миллионов записей по одной занимает все ваше время, поэтому вы тоже не можете этого сделать (т.е. ваша первоначальная модель чтения в файл).

Итак ... вам придется пойти на компромисс и сделать немного того и другого.

У Джоша все в порядке - откройте курсор к вашей БД, который просто читает следующую запись, одну за другой, самым простым и наиболее функциональным способом. Курсор «пожарного шланга» (иначе известный как «только для чтения» и «только вперед») - это то, что вам нужно, так как он создает наименьшую нагрузку на базу данных. БД не позволит вам обновлять записи или возвращаться назад в наборе записей, который вам все равно не нужен, поэтому ему не нужно обрабатывать память для записей.

Теперь у вас есть этот курсор, вам дается 1 запись за один раз БД - прочитайте ее и запишите в файл (или несколько файлов), это должно закончиться довольно быстро. Ваша задача - объединить файлы в 1 в правильном порядке, что относительно просто.

Учитывая количество записей, которые вы должны обработать, я думаю, что это оптимальное решение для вас.

Но ... в любом случае, если у вас все хорошо, почему бы просто не уменьшить количество потоков, пока вы не выйдете за пределы своей памяти. Пакетная обработка запускается в одночасье во многих компаниях, это просто еще один из тех процессов.

0 голосов
/ 18 мая 2009

Зависит от используемой вами базы данных, но если бы это был SQL Server, я бы порекомендовал использовать для этого что-то вроде SSIS, а не писать программу.

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