我在oracle中有一个表:
id (long), img1 (blob),img2 (blob)...img10 (blob), created (date)
该表有大约3000万条记录。 (30000000)
我想将这些图像加载到像HashMap< id, HashMap<Integer,byte[]>>
按顺序加载3000万条记录的时间非常长。有没有办法在parellel中加载数据?
编辑:我使用此查询来检索数据:
SELECT img1,img2,img3,...
FROM images
WHERE ID IN (SELECT ID FROM (SELECT A.*, ROWNUM RNUM FROM (SELECT ID FROM images) A
WHERE ROWNUM <=end) WHERE RNUM >=start);
答案 0 :(得分:3)
按顺序加载3000万条记录的时间非常长。 有没有办法在parellel中加载数据?
我们正在讨论千兆字节的数据。此过程的瓶颈很可能是应用程序 - 数据库网络连接的吞吐量。在1gbps网络上,您可以实现的有效传输速率约为每秒85-100 MB。例如,对于100 gb,转移应至少需要1000秒,即约为16,7分钟。
如果您的界面被其他任何东西使用,您的oracle-app转移将会更小。如果数据库中有几个路由器走了,时间会因协议开销增加而增加。因此,读取时间会更长。
答案 1 :(得分:3)
您必须考虑此解决方案中的IO瓶颈,但使用该RAM我假设您拥有一个大主机。还要考虑CPU不是问题,但网络流量+磁盘流量是关键。
话虽如此,我认为你有一个疯狂的网络和磁盘带宽。
在此解决方案中,您必须注意:
要使用它,您必须执行:
String url = ...your JDBC url
String user = ...your Oracle user
String pass = ...your password
int num_of_threads;
ParallelReader r = new ParallelReader(url, user, pass);
HashMap< Long, HashMap<Integer, byte[]>> map = r.read(num_of_threads);
ParallelReader的代码是:
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
class ParallelReader {
private final String url;
private final String user;
private final String pass;
public ParallelReader(String url, String user, String pass) {
this.url = url;
this.user = user;
this.pass = pass;
}
public HashMap< Long, HashMap<Integer, byte[]>> read(int numthreads) {
HashMap<Long, HashMap<Integer, byte[]>> unsafe_map = new HashMap<>();
ConcurrentHashMap<Long, HashMap<Integer, byte[]>> safe_map = new ConcurrentHashMap<>(unsafe_map);
Worker pool[] = new Worker[numthreads];
for (int i = 0; i < numthreads; i++)
pool[i] = new Worker(i, numthreads, safe_map);
for (Worker w : pool)
w.start();
try {
for (Worker w : pool)
w.join();
} catch (InterruptedException ex) {
Logger.getLogger(ParallelReader.class.getName()).log(Level.SEVERE, null, ex);
}
return unsafe_map;
}
private class Worker extends Thread {
private final long mod;
private final long max;
private final ConcurrentHashMap<Long, HashMap<Integer, byte[]>> safe_map;
public Worker(long mod, long max, ConcurrentHashMap<Long, HashMap<Integer, byte[]>> safe_map) {
this.mod = mod;
this.max = max;
this.safe_map = safe_map;
}
@Override
public void run() {
try (Connection conn = DriverManager.getConnection(url, user, pass)) {
PreparedStatement pstmt = conn.prepareStatement(
"SELECT img1, img2, img3, img4, img5, img6, img7, img8, img9, img10, id "
+ "FROM images "
+ "WHERE MOD(id, ?) = ?");
pstmt.setLong(1, max);
pstmt.setLong(2, mod);
ResultSet rset = pstmt.executeQuery();
while (rset.next()) {
long id = rset.getLong(11);
HashMap<Integer, byte[]> imgs = new HashMap<>();
for (int i = 1; i <= 10; i++) {
Blob b = rset.getBlob(i);
byte bytes[] = b.getBytes((long) 1, (int) b.length());
imgs.put(i, bytes);
}
safe_map.put(id, imgs);
}
} catch (SQLException ex) {
Logger.getLogger(ParallelReader.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
答案 2 :(得分:2)
您可以并行查询数据库切片表,但是在编写记录时应该锁定哈希表。我认为你不会比批量阅读表更快。 根据我的经验,瓶颈是内存分配:在内存中分配30M对象对您的系统来说是一项巨大的工作。 无论你想在内存中使用30M记录做什么,都要尝试在数据库中执行:它们用于管理大量数据并针对它进行优化