Java 多次查询庞大的集合。是否有更高性能的解决方案?
我需要您对以下代码的性能瓶颈/改进方面的专业知识 我有一个庞大的利率集合(~250万个对象),需要反复遍历,获取并返回拟合条目列表。我目前的解决方案是一个HSQL内存数据库: 利率表结构: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
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更快的方法来按照查询逻辑重复获取对象吗?是否有更好/更快/任何数据结构
- 有趣的是,我使用多线程和ExecutorService的实验并没有真正改变任何性能方面的变化
欢迎任何提示、想法或任何东西 我的观点是,当我们处理大量数据时,内存数据库可能会产生问题,因为除非使用分布式内存数据库,否则它将消耗非常大的内存
另一种选择是,如果不使用分布式内存数据库,可以使用具有合适的逐出策略等的缓存。我的观点是,当我们处理非常大量的数据时,内存数据库可能会产生问题,因为除非使用分布式内存数据库,否则它将消耗非常大的内存
另一种选择是,如果不使用分布式内存数据库,可以使用缓存和合适的逐出策略等。我认为内存数据库不是解决这个问题的好方法。最重要的是避免全表扫描。我觉得你的索引是对的。这将有助于看到真正的计时,应该是毫秒
如果这还不够,您可以将整个结构作为嵌套索引集合或哈希表加载到内存中,并使用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秒:)另外,我变得更聪明了——我以前从未使用过树形图/树集,也没有