Запрашивать огромную коллекцию несколько раз.

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

У меня есть огромная коллекция (~ 2,5 миллиона объектов) INTEREST_RATES, чтобы многократно проходить и извлекать и возвращать списки подходящих записей. Мое текущее решение для этого - база данных памяти HSQL:

Структура таблицы INTEREST_RATE :

CREATE MEMORY TABLE INTEREST_RATES " +
"(EFFECTIVE_DATE DATE not NULL, "
+ "INTEREST_RATE DOUBLE not NULL, "
+ "INTEREST_RATE_CD INT not NULL, "
+ "INTEREST_RATE_TERM INT not NULL, "
+ "INTEREST_RATE_TERM_MULT VARCHAR(5) not NULL,"
+ "TERM_IN_DAYS DOUBLE not NULL,"
+ "PRIMARY KEY (EFFECTIVE_DATE, INTEREST_RATE_CD, INTEREST_RATE_TERM, INTEREST_RATE_TERM_MULT))"

CREATE INDEX dtidx ON INTEREST_RATES (EFFECTIVE_DATE, INTEREST_RATE_CD)

Запрос :

SELECT * from INTEREST_RATES where INTEREST_RATE_CD = ? and 
EFFECTIVE_DATE = (SELECT MAX(EFFECTIVE_DATE) from INTEREST_RATES 
where INTEREST_RATE_CD = ? AND EFFECTIVE_DATE <= ?)

-> Итак, я пытаюсь получить последние доступные ЦЕНЫ для определенного INTEREST_RATE_CD, давая верхний предел даты.

Java-часть для выполнения запроса :

PreparedStatement p = con.prepareStatement(sql);
p.setLong(1, intRateCd);
p.setLong(2, intRateCd);
p.setDate(3, someDate);

ResultSet r = p.executeQuery();
return resultSetToList(r);

Основной цикл Java с использованием Futures / многопоточности :

ExecutorService executor  = Executors.newFixedThreadPool(4);
CompletionService<TestResult> completionService = new ExecutorCompletionService<>(executor);
long futureCount = 0;

while(deals.next()) //deals is a ScrollableResults set from Hibernate
{                       
    IDealEntity deal = (IDealEntity) deals.get()[0];

    //These tasks contain the INTEREST_RATE query action
    QueryTask task = new QueryTask(some params...);
    completionService.submit(task);     
}           

try 
{               
    while(futureCount < dealCount)
    {
        Future<TestResult> result = completionService.take();
        TestResult testResult = result.get();
        futureCount++;

        testResults.add(testResult);
    }

    executor.shutdown();
    executor.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
} 
catch (Exception ex) 
{                   
    ex.printStackTrace();
}

Теперь, когда я пытаюсь улучшить производительность или найти ошибки в моем коде, мои вопросы будут такими:

  • Не могли бы вы придумать что-нибудь быстрее, чем inmem db, для многократного извлечения объектов, следуя логике запроса? Есть ли лучше / быстрее / без структуры данных?

Пока что HSQL был самым быстрым, что я мог придумать. Также попробовал H2, который был waaaaay медленнее.

  • Интересно, что мой эксперимент с использованием многопоточности и ExecutorService на самом деле ничего не меняет с точки зрения производительности.

Почти нет разницы, если я использую 1 размер ThreadPool или 4 потока ...

Любые советы, идеи или что-либо приветствуется!

Всего 2 ответа


Я не думаю, что в базе данных памяти хороший подход для ее решения. Самое главное, чтобы избежать полного сканирования таблицы. Мне кажется, что у вас есть правильные индексы. Было бы полезно увидеть реальные сроки, которые должны составлять миллисекунды.

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


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

Другой альтернативой, если не использовать распределенную базу данных в памяти, может быть использование Cache с хорошо подходящими политиками вытеснения и т. Д.


Есть идеи?

10000