【问题标题】:execute query on table that contains billions of record [duplicate]对包含数十亿条记录的表执行查询
【发布时间】:2014-09-20 10:46:37
【问题描述】:

我想在不使用限制子句的情况下从数据库中获取一些记录(它可以是 50,100 或用户配置的其他内容),因为我们的应用程序可能在多个数据库上工作,例如 mysql、oracle、mssql、db2....

我做了以下解决方案

package com.test;

import java.sql.Connection;
import java.sql.Statement;
import java.sql.ResultSet;
import java.sql.DriverManager;
import java.util.Date;

public class BatchRetrieveTest extends Object {
    private static final int FETCH_SIZE = 10;

    public BatchRetrieveTest() {
    }

    public static void main(String[] args) {
        BatchRetrieveTest batchRetrieveTest = new BatchRetrieveTest();
        batchRetrieveTest.test();
    }

    void test() {
        Connection conn = null;
        Statement stmt2 = null;
        Date start = null;
        Date end = null;
        int i = 0;
        try {
            conn = DriverManager.getConnection(
                    "jdbc:mysql://localhost:3306/test",
                    "root", "root");
            stmt2 = conn.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE,
                    ResultSet.CONCUR_READ_ONLY);
            conn.setAutoCommit(false);
            stmt2.setFetchSize(FETCH_SIZE);
            stmt2.setPoolable(true);
            start = new Date();
            System.out.println(new Date() + "second execute start"
                    + new Date().getTime());
            ResultSet rs2 = stmt2
                    .executeQuery("SELECT * FROM sample_final_attendance limit 1000");

            end = new Date();
            System.out.println(new Date() + "*************second execute end"
                    + (end.getTime() - start.getTime()));
            rs2.absolute(200000);
            i = 0;
            while (rs2.next()) {
                if (i++ > 100) {
                    break;
                }
            }
            rs2.close();
            stmt2.close();
            end = new Date();
            System.out.println(new Date() + "second read end"
                    + (end.getTime() - start.getTime()));
            conn.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                stmt2.close();
                conn.close();
            } catch (Exception e) {
            }
        }
    }
}

这里 sample_final_attendance 表包含 15 列和 320 万条记录 执行此程序时需要 2GB 内存和 47 秒的执行时间

我想知道如果某个表有数十亿条记录,那么它会执行失败

我也按照建议使用了setFetchSize,但问题是一样的

请提出一些解决方案

提前致谢

【问题讨论】:

  • @Scary Wombat 没错,但这在其他数据库中不起作用我想要适用于所有数据库的通用解决方案
  • 这段代码是如何工作的? SQL 语句的LIMIT 子句说让我获得前 1000 行,然后移动到结果集的第 200,000 行。我原以为你最终会得到rs2.next() 返回false,而while 循环什么也不做。我错过了什么?
  • 我使用了 ResultSet.TYPE_SCROLL_SENSITIVE 所以你可以向前移动到你想要移动的记录
  • 但是您有一个最多包含 1000 行的结果集,并且您移动到第 200,000 行 - 这将如何工作?
  • 我将 fetchsize 设置为 1000 而不是 maxfetchsize 所以它可以工作

标签: java jdbc


【解决方案1】:

我们在 Statement Object 中设置了 setMaxRow(int numOfRow),这将限制 Statement Object 生成的行数,而忽略剩余的行数。

看看文档。

【讨论】:

  • 什么文档?为什么不提供 OP 的链接?
  • @dilly 当我想获取最后 100 条记录时会发生什么,而且这不是正确的方法
  • 嗨 macfij,我的意思是 java 文档 docs.oracle.com/javase/7/docs/api/java/sql/…
【解决方案2】:

好吧,ASFAIK 明白,这个问题与多语言存储中的数据处理更相关。如果您认为,您需要在所有相互依赖的数据库类型的情况下解决相同的问题——一种常见的方法是构建一个服务层。

服务层可以是缓存库,甚至是您创建的地图。不要尝试一次查询有大量记录的数据库,而是将数据作为批处理,并将其存储为 pojos 池。根据用户的需求,您可以从服务层提供数据。

您可以使用 memcache 或 hazlecast 或许多其他缓存库,它们可以直接与数据库集成。我真的不知道你的情况有多复杂。我提出的是一个建议。这构成了一个数据网格,可以在后台填充来自任何数据库的数据。

【讨论】:

  • 感谢您的回复,这是正确的,我需要创建提供数据的层,但我想要限制一次返回的记录数量的解决方案,我在 statement 上使用了 setFetchSize,但执行了该语句需要这么多时间和内存几乎 2GB 内存所以有什么方法可以在 2-3 mb 内存和 2-3 秒内执行查询
猜你喜欢
  • 1970-01-01
  • 2019-12-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-02
  • 1970-01-01
相关资源
最近更新 更多