use*_*404 8 java sql multithreading jdbc
我在我的 java 应用程序中执行以下语句集。它连接到一个 oracle 数据库。
stat=connection.createStatement();
stat1=commection.createstatement();
ResultSet rs = stat.executeQuery(BIGQUERY);
while(rs.next()) {
obj1.setAttr1(rs.getString(1));
obj1.setAttr2(rs.getString(1));
obj1.setAttr3(rs.getString(1));
obj1.setAttr4(rs.getString(1));
ResultSet rs1 = stat1.executeQuery(SMALLQ1);
while(rs1.next()) {
obj1.setAttr5(rs1.getString(1));
}
ResultSet rs2 = stat1.executeQuery(SMALLQ2);
while(rs2.next()) {
obj1.setAttr6(rs2.getString(1));
}
.
.
.
LinkedBlockingqueue.add(obj1);
}
//all staements and connections close
Run Code Online (Sandbox Code Playgroud)
在BIGQUERY约4.5万条记录,并为每个记录返回,我必须执行较小的查询,这是在14号。每个小查询都有 3 个内部连接语句。
我的多线程应用程序现在可以在一小时内处理 90,000 个。但是我可能每天都要运行代码,所以我想在 20 小时内处理所有记录。我正在使用大约 200 个线程来处理上述代码并将记录存储在链接的阻塞队列中。
盲目地增加线程数有助于提高性能还是有其他方法可以提高结果集的性能?
PS:我无法在此处发布查询,但我确信所有查询都已优化。
为了提高您的场景的 JDBC 性能,您可以应用一些修改。
正如您将看到的,所有这些修改都可以显着加快您的任务。
1.使用批量操作。
您可以读取大查询并将结果存储在某种缓冲区中。只有当缓冲区已满时,您才应该对缓冲区中收集的所有数据运行子查询。这显着减少了要执行的 SQL 语句的数量。
static final int BATCH_SIZE = 1000;
List<MyData> buffer = new ArrayList<>(BATCH_SIZE);
while (rs.hasNext()) {
MyData record = new MyData( rs.getString(1), ..., rs.getString(4) );
buffer.add( record );
if (buffer.size() == BATCH_SIZE) {
processBatch( buffer );
}
}
void processBatch( List<MyData> buffer ) {
String sql = "select ... where X and id in (" + getIDs(buffer) + ")";
stat1.executeQuery(sql); // query for all IDs in buffer
while(stat1.hasNext()) { ... }
...
}
Run Code Online (Sandbox Code Playgroud)
2. 使用高效的地图来存储来自多个选择的内容。
如果您的记录没有那么大,您可以将它们全部存储在 400 万个表中。
我在夜间进程中多次使用这种方法(没有普通用户)。这种方法可能需要很多堆内存(即 100 MB - 1 GB)——但比方法 1) 要快得多。
要做到这一点,您需要高效的地图实现,即 - gnu.trove.map.TIntObjectMap (etc) 这比 java 标准库地图要好得多。
final TIntObjectMap<MyData> map = new TIntObjectHashMap<MyData>(10000, 0.8f);
// query 1
while (rs.hasNext()) {
MyData record = new MyData( rs.getInt(1), rs.getString(2), ..., rs.getString(4) );
map.put(record.getId(), record);
}
// query 2
while (rs.hasNext()) {
int id = rs.getInt(1); // my data id
String x = rs.getString(...);
int y = rs.getInt(...);
MyData record = map.get(id);
record.add( new MyDetail(x,y) );
}
// query 3
// same pattern as query 2
Run Code Online (Sandbox Code Playgroud)
在此之后,您的地图已填充了收集的所有数据。可能分配了大量内存。这就是为什么只有在拥有此类资源时才能使用该方法的原因。
另一个主题是如何将 MyData 和 MyDetail 类编写得尽可能小。你可以使用一些技巧:
3. 交易
如果您必须进行一些更新或插入,则超过 400 万条记录对于事务处理来说太多了。这对于大多数数据库配置来说太多了。使用方法 1) 并为每个批次提交事务。在每个新插入的记录上,您可以有类似 RUN_ID 的内容,如果一切顺利,您可以将此 RUN_ID 标记为成功。
如果您的查询只是读取 - 没有问题。但是,您可以将事务标记为只读以帮助您的数据库。
4. Jdbc 获取大小。
当您从数据库加载大量记录时,在 jdbc 连接上设置适当的获取大小非常非常重要。这减少了对数据库套接字的物理命中次数并加快了进程。
例子:
// jdbc
statement.setFetchSize(500);
// spring
JdbcTemplate jdbc = new JdbcTemplate(datasource);
jdbc.setFetchSize(500);
Run Code Online (Sandbox Code Playgroud)
在这里您可以找到一些使用 fetch size 的基准和模式:
http://makejavafaster.blogspot.com/2015/06/jdbc-fetch-size-performance.html
5. 准备好的语句
使用 PreparedStatement 而不是 Statement。
6. sql 语句数。
始终尽量减少发送到数据库的 sql 语句的数量。
| 归档时间: |
|
| 查看次数: |
26572 次 |
| 最近记录: |