Многократный запрос огромной коллекции. Есть ли более эффективное решение? - PullRequest
1 голос
/ 14 мая 2019

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

У меня есть огромная коллекция (~ 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, который был намного медленнее.

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

Это почти без разницы, еслиЯ использую 1 размер ThreadPool или 4 темы ...

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

Ответы [ 2 ]

0 голосов
/ 14 мая 2019

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

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

0 голосов
/ 14 мая 2019

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

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

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