从oracle表到内存

时间:2015-07-09 07:46:24

标签: java database oracle

我在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);

3 个答案:

答案 0 :(得分:3)

  

按顺序加载3000万条记录的时间非常长。   有没有办法在parellel中加载数据?

我们正在讨论千兆字节的数据。此过程的瓶颈很可能是应用程序 - 数据库网络连接的吞吐量。在1gbps网络上,您可以实现的有效传输速率约为每秒85-100 MB。例如,对于100 gb,转移应至少需要1000秒,即约为16,7分钟。

如果您的界面被其他任何东西使用,您的oracle-app转移将会更小。如果数据库中有几个路由器走了,时间会因协议开销增加而增加。因此,读取时间会更长。

答案 1 :(得分:3)

您必须考虑此解决方案中的IO瓶颈,但使用该RAM我假设您拥有一个大主机。还要考虑CPU不是问题,但网络流量+磁盘流量是关键。

话虽如此,我认为你有一个疯狂的网络和磁盘带宽。

在此解决方案中,您必须注意:

  • 我使用Java long类型来读取id的Oracle编号(如果你的实际数字超过Java long max值那么你必须使用BigInteger)
  • HashMap不是线程安全的,因此在填充时必须使用ConcurrentHashMap来包装不安全的HashMap。
  • 我使用MOD而不是rownum来拆分表(但很容易将查询转换为使用rownum(您的解决方案)或width_bucket功能)。
  • 只需一步即可读取blob(因此图像大小不能超过Integer.MAX_VALUE;如果它们可以更大,则使用循环或其他读取方法)。

要使用它,您必须执行:

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记录做什么,都要尝试在数据库中执行:它们用于管理大量数据并针对它进行优化