Как повысить производительность Java-приложения, извлекающего большие данные из базы данных Oracle? - PullRequest
1 голос
/ 02 декабря 2010

У меня есть 3 таблицы базы данных - Предметы, Аудиты и Комментарии. Мне нужно извлечь большой объем данных из таблицы Items , скажем, 1 миллион записей, и для каждого выбранного элемента мне нужно извлечь данные из Audits и Comments и запишите отчет в файл с разделителями. Таким образом, результат может выглядеть следующим образом:

Item entry 1
    Audit entry 1 for Item 1
    Audit entry 2 for Item 1
    Audit entry 3 for Item 1
    Comment entry 1 for Item 1
    Comment entry 2 for Item 1
Item entry 2 
    Audit entry 1 for Item 2
    .
    .
    .

Теперь это занимает так много времени, потому что программа запрашивает оракула 1 миллион раз для каждого элемента . Я хотел бы увеличить производительность через потоки, но я не знаком с потоками. Так может кто-нибудь помочь мне с увеличением производительности?

Ответы [ 8 ]

3 голосов
/ 02 декабря 2010

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

Способ ускорить результаты запроса - вернуть строку выбора в виде единой объединенной строки и разбить ее самостоятельно. Это использовалось для ускорения поиска в 2-3 раза. Новые версии Oracle могут быть умнее в этом отношении и иметь меньше накладных расходов.

Однако объем данных, которые у вас есть, в любом случае, вероятно, потребуется некоторое время, чтобы получить от Oracle.

2 голосов
/ 02 декабря 2010

Прочитайте этот ресурс: http://www.w3schools.com/Sql/sql_join.asp и используйте объединение.

1 голос
/ 03 декабря 2010

Вы можете написать хранимую процедуру, которая будет выводить файл с пакетом utl_file, и просто вызывать его из Java. Таким образом, вы можете просто использовать что-то вроде

f := utl_file.fopen('my_dir','my_file','w');
FOR r_items IN (SELECT * FROM items) LOOP
  utl_file.put_line(f,r_items.name);

  FOR r_audit IN (SELECT * FROM audit WHERE item_id = r_items.id) LOOP
    utl_file.put_line(f,r_audit.some_field);
  END LOOP;

  FOR r_comments IN (SELECT * FROM comments WHERE item_id = r_items.id) LOOP
    utl_file.put_line(f,r_comments.some_field);
  END LOOP;
END LOOP;
1 голос
/ 02 декабря 2010

Неясно, что вы делаете, и какова ваша настоящая проблема из предоставленной вами ограниченной информации.

  • Если вы выполняете миллион отдельных (небольших) запросов, вам следует подумать о реструктуризации приложения, чтобы оно объединяло их в пакеты или выполняло SELECT по всей таблице.

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

0 голосов
/ 04 декабря 2010

Если ваша система (аппаратное обеспечение, конфигурация и т. Д.) Рассчитана на объем данных, которые вы в нее помещаете, лучший, самый быстрый и простой способ - просто объединить таблицы в одном запросе, извлечь строки (см. Другие комментарии о fetch_size), а затем выгрузите его в любом формате.

Исходя из примера выходного формата, вам нужно обрабатывать строки в отсортированном порядке (элемент, аудит, комментарии). Вы перебираете строки и отслеживаете последний обработанный элемент, и всякий раз, когда текущий ITEM_ID отличается от предыдущего, вы выводите данные элемента.

Единственный наиболее важный аспект, который необходимо учитывать при принятии решения о том, как реализовать это, - вписывается ли объединение и сортировка в память или нет. Если сортировка / объединение разлится на диск, вам придется обойти это, чтобы добиться желаемой производительности. Некоторые примеры того, как избежать разлива диска:

Хэшируйте таблицы (или их копии) по ITEM_ID. Затем вы можете объединить таблицы по частям так, чтобы каждое объединение помещалось в памяти.

Или вы можете получить все данные из всех таблиц, а в своем Java-коде поместить элементы в связанный список, а аудит / комментарии - в какую-нибудь хеш-структуру, основанную на item_no. Затем вы перебираете элементы и запрашиваете аудит / комментарии по item_id. Это решение позволяет избежать операции сортировки и не требует размещения объединенного результата в памяти.

Или вы можете реализовать самостоятельное разбиение. Например, запросить данные 9 раз. В первом запросе вы выбираете только элементы с ITEM_ID, начинающимися или заканчивающимися на 1. Во втором запросе выбираются все элементы, начинающиеся / заканчивающиеся на 2 и так далее. Это решение приводит к сканированию 9 таблиц на всех таблицах, что явно не очень эффективно. Но если вам удастся избежать разлива на диск, он на самом деле может быть быстрее.

0 голосов
/ 03 декабря 2010

После того, как вы управляете UNION / JOIN, как сказал BazzPsychoNut, может быть полезно настроить значение FetchSize на большее значение, если ResultSet велик. Значение по умолчанию для Oracle - 10.

Statement stmt = conn.createStatement();
stmt.setFetchSize(200);
ResultSet rset = stmt.executeQuery(sql);

См. Получить большой ResultSet

0 голосов
/ 03 декабря 2010

Моя мысль - выполнить три запроса (один для возврата всех элементов, один для всех комментариев и один для всех записей аудита), каждый из которых отсортирован по идентификатору элемента

SELECT * FROM
  (SELECT itemid, 1 type, null seq, item_line line
   from items
   union all
   select itemid, 2, audit_seq, audit_line
   from audit
   union all
   select itemid, 3, comment_seq comment_line 
   from comments)
order by itemid, type, seq

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

0 голосов
/ 02 декабря 2010

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

select itm.itemid
,      tmp.what || ' ' || tmp.entry || ' for Item ' || tmp.itemid line
from   items itm
join
(
    select itemid
    ,      entry 
    ,      'Audit' what
    from   audits
    union all
    select itemid
    ,      entry 
    ,      'Comment' what
    from   comments
) tmp on itm.itemid = tmp.itemid
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...