多次查询一个巨大的集合。有没有更高效的解决方案?
Querying a huge collection multiple times. Is there a more performant solution?
我需要你使用以下代码了解性能 bottlenecks/improvements。
我有一个巨大的 INTEREST_RATES 集合(约 250 万个对象)可以重复遍历和获取以及 return 个合适的条目列表。我目前的解决方案是 HSQL 内存数据库:
INTEREST_RATE table 结构:
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 的最新可用 RATES,给出日期上限。
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/multithreading:
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 数据库更快的方法来按照查询逻辑重复获取对象吗?有没有更好/更快/什么数据结构?
到目前为止,HSQL 是我能想到的最快的东西。还尝试了 H2,但速度很慢。
- 有趣的是,我使用多线程和 ExecutorService 的实验并没有真正改变任何性能。
如果我使用 1 个大小的 ThreadPool 或 4 个线程几乎没有区别...
欢迎任何提示或想法或任何东西!
我的观点是,当我们处理大量数据时,in-memory 数据库可能会产生问题,因为它会消耗非常大的内存,除非使用分布式 in-memory 数据库。
另一种选择,如果不使用分布式 in-memory 数据库,可以使用具有非常合适的驱逐策略等的缓存。
我不认为内存数据库是解决它的好方法。最重要的是避免完整 table 扫描。在我看来,您的索引是正确的。查看应为毫秒的实际时间会很有用。
如果这还不够,您可以将整个结构作为嵌套索引集合或散列 table 加载到内存中,并使用 java 直接遍历它们。
我需要你使用以下代码了解性能 bottlenecks/improvements。
我有一个巨大的 INTEREST_RATES 集合(约 250 万个对象)可以重复遍历和获取以及 return 个合适的条目列表。我目前的解决方案是 HSQL 内存数据库:
INTEREST_RATE table 结构:
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 的最新可用 RATES,给出日期上限。
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/multithreading:
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 数据库更快的方法来按照查询逻辑重复获取对象吗?有没有更好/更快/什么数据结构?
到目前为止,HSQL 是我能想到的最快的东西。还尝试了 H2,但速度很慢。
- 有趣的是,我使用多线程和 ExecutorService 的实验并没有真正改变任何性能。
如果我使用 1 个大小的 ThreadPool 或 4 个线程几乎没有区别...
欢迎任何提示或想法或任何东西!
我的观点是,当我们处理大量数据时,in-memory 数据库可能会产生问题,因为它会消耗非常大的内存,除非使用分布式 in-memory 数据库。
另一种选择,如果不使用分布式 in-memory 数据库,可以使用具有非常合适的驱逐策略等的缓存。
我不认为内存数据库是解决它的好方法。最重要的是避免完整 table 扫描。在我看来,您的索引是正确的。查看应为毫秒的实际时间会很有用。
如果这还不够,您可以将整个结构作为嵌套索引集合或散列 table 加载到内存中,并使用 java 直接遍历它们。