Java 多次查询庞大的集合。是否有更高性能的解决方案?

Java 多次查询庞大的集合。是否有更高性能的解决方案?,java,performance,collections,in-memory-database,Java,Performance,Collections,In Memory Database,我需要您对以下代码的性能瓶颈/改进方面的专业知识 我有一个庞大的利率集合(~250万个对象),需要反复遍历,获取并返回拟合条目列表。我目前的解决方案是一个HSQL内存数据库: 利率表结构: CREATE MEMORY TABLE INTEREST_RATES " + "(EFFECTIVE_DATE DATE not NULL, " + "INTEREST_RATE DOUBLE not NULL, " + "INTEREST_RATE_CD INT not NULL, " + "INTERES

我需要您对以下代码的性能瓶颈/改进方面的专业知识

我有一个庞大的利率集合(~250万个对象),需要反复遍历,获取并返回拟合条目列表。我目前的解决方案是一个HSQL内存数据库:

利率表结构

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 <= ?)
PreparedStatement p = con.prepareStatement(sql);
p.setLong(1, intRateCd);
p.setLong(2, intRateCd);
p.setDate(3, someDate);

ResultSet r = p.executeQuery();
return resultSetToList(r);
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();
}
查询

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 <= ?)
PreparedStatement p = con.prepareStatement(sql);
p.setLong(1, intRateCd);
p.setLong(2, intRateCd);
p.setDate(3, someDate);

ResultSet r = p.executeQuery();
return resultSetToList(r);
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();
}
使用未来/多线程的Java主循环

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 <= ?)
PreparedStatement p = con.prepareStatement(sql);
p.setLong(1, intRateCd);
p.setLong(2, intRateCd);
p.setDate(3, someDate);

ResultSet r = p.executeQuery();
return resultSetToList(r);
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();
}
ExecutorService executor=Executors.newFixedThreadPool(4);
CompletionService CompletionService=新的执行者CompletionService(执行者);
长期未来计数=0;
while(deals.next())//deals是Hibernate中的可滚动结果集
{                       
IDealEntity deal=(IDealEntity)deals.get()[0];
//这些任务包含利率查询操作
QueryTask任务=新的QueryTask(一些参数…);
completionService.submit(任务);
}           
尝试
{               
while(futurecont
现在,, 当我试图提高性能或发现代码中的错误时, 我的问题是:

  • 您能想出比inmemdb更快的方法来按照查询逻辑重复获取对象吗?是否有更好/更快/任何数据结构
到目前为止,HSQL是我能想到的最快的东西。还尝试了H2,速度很慢

  • 有趣的是,我使用多线程和ExecutorService的实验并没有真正改变任何性能方面的变化
如果我使用1个大小的线程池或4个线程,几乎没有什么区别


欢迎任何提示、想法或任何东西

我的观点是,当我们处理大量数据时,内存数据库可能会产生问题,因为除非使用分布式内存数据库,否则它将消耗非常大的内存


另一种选择是,如果不使用分布式内存数据库,可以使用具有合适的逐出策略等的缓存。

我的观点是,当我们处理非常大量的数据时,内存数据库可能会产生问题,因为除非使用分布式内存数据库,否则它将消耗非常大的内存


另一种选择是,如果不使用分布式内存数据库,可以使用缓存和合适的逐出策略等。

我认为内存数据库不是解决这个问题的好方法。最重要的是避免全表扫描。我觉得你的索引是对的。这将有助于看到真正的计时,应该是毫秒


如果这还不够,您可以将整个结构作为嵌套索引集合或哈希表加载到内存中,并使用java直接遍历这些集合或哈希表

我认为内存数据库不是解决这个问题的好方法。最重要的是避免全表扫描。我觉得你的索引是对的。这将有助于看到真正的计时,应该是毫秒


如果这还不够,您可以将整个结构作为嵌套索引集合或哈希表加载到内存中,并使用java直接遍历这些集合或哈希表

这可能与codereview.stackexchange.com相匹配,但不确定。无论如何,内存中的操作是最有效的。因为有子查询之类的关系,所以不能使用ElasticSearch之类的东西,只要它不支持AFAIK子查询。我认为减少查询数量的唯一方法是将您的
交易
(在ScrollableResultSet中)分组,以便单个组具有相同的参数集,这些参数将在相同的查询中转换,因此在相同的查询结果中,可以在该交易组中重用Hanks Nikolay,通过进一步的聚类,我会想到你在说什么!你知道为什么更多的线程不能带来更好的性能吗?我认为4个线程(例如处理器内核)在RAM中的浏览速度会比1快,但不会。这可能与codereview.stackexchange.com相匹配,但不确定。无论如何,内存中的操作是最有效的。因为有子查询之类的关系,所以不能使用ElasticSearch之类的东西,只要它不支持AFAIK子查询。我认为减少查询数量的唯一方法是将您的
交易
(在ScrollableResultSet中)分组,以便单个组具有相同的参数集,这些参数将在相同的查询中转换,因此在相同的查询结果中,可以在该交易组中重用Hanks Nikolay,通过进一步的聚类,我会想到你在说什么!你知道为什么更多的线程不能带来更好的性能吗?我认为4个线程(例如处理器内核)浏览RAM的速度会比1快,但没有……我做了一点时间测量:35434次查询需要290秒(约5分钟),因此我有大约122次调用/秒。你认为HashMap的HashMap会更快吗?就像第一个以INT_RATE_CD为键的映射一样,内部也有(排序)哈希映射,其有效日期为键,并包含一个利率对象列表?从时间上看,我会说索引工作正常,如果使用以利率为键的哈希表和按有效日期排序的树映射,这将是最快的,我预计会有1000倍的震级。但是想想更新吧。我目前正在实施TreeMap解决方案,我会回来告诉你它是如何运行的!好的,我已经完成了,现在35k笔交易是以。。。1-2秒:)另外,我变得更聪明了——我以前从未使用过树形图/树集,也没有