以极高的速度获取行

2024-03-28

我在 Oracle 中有一个非常大的表(数亿行,包含数字和字符串),我需要读取该表的所有内容,对其进行格式化并写入文件或任何其他资源。 一般来说,我的解决方案如下所示:

package my.odp;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.lang.Throwable;
import java.sql.*;


public class Main {
public static volatile boolean finished = false;

public static void main(final String[] args) throws InterruptedException {
    final ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(10000);
    final Thread writeWorker = new Thread("ODP Writer") {
        public void run() {
            try {
                File targetFile = new File(args[0]);
                FileWriter fileWriter = new FileWriter(targetFile);
                BufferedWriter writer = new BufferedWriter(fileWriter);
                String str;
                try {
                    while (!finished) {
                        str = queue.poll(200, TimeUnit.MILLISECONDS);
                        if (str == null) {
                            Thread.sleep(50);
                            continue;
                        }
                        writer.write(str);
                        writer.write('\n');
                    }
                } catch (InterruptedException e) {
                    writer.close();
                    return;
                }
            }
            catch (Throwable e) {
                e.printStackTrace();
                return;
            }
        }
    };

    final Thread readerThread = new Thread("ODP Reader") {
        public void run() {
            try {
                Class.forName("oracle.jdbc.OracleDriver");
                Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@//xxx.xxx.xxx.xxx:1521/orcl", "user", "pass");

                Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
                stmt.setFetchSize(500000);
                ResultSet rs = stmt.executeQuery("select * from src_schema.big_table_view");
                System.out.println("Fetching result");
                while (rs.next()) {
                    StringBuilder sb = new StringBuilder();
                    sb.append(rs.getString(1)).append('\t');//OWNER
                    sb.append(rs.getString(2)).append('\t');//OBJECT_NAME
                    sb.append(rs.getString(3)).append('\t');//SUBOBJECT_NAME
                    sb.append(rs.getLong(4)).append('\t');//OBJECT_ID
                    sb.append(rs.getLong(5)).append('\t');//DATA_OBJECT_ID
                    sb.append(rs.getString(6)).append('\t');//OBJECT_TYPE
                    sb.append(rs.getString(7)).append('\t');//CREATED
                    sb.append(rs.getString(8)).append('\t');//LAST_DDL_TIME
                    sb.append(rs.getString(9)).append('\t');//TIMESTAMP
                    sb.append(rs.getString(10)).append('\t');//STATUS
                    sb.append(rs.getString(11)).append('\t');//TEMPORARY
                    sb.append(rs.getString(12)).append('\t');//GENERATED
                    sb.append(rs.getString(13)).append('\t');//SECONDARY
                    sb.append(rs.getString(14)).append('\t');//NAMESPACE
                    sb.append(rs.getString(15));//EDITION_NAME
                    queue.put(sb.toString());
                }

                rs.close();
                stmt.close();
                conn.close();
                finished = true;
            } catch (Throwable e) {
                e.printStackTrace();
                return;
            }
        }
    };
    long startTime = System.currentTimeMillis();
    writeWorker.start();
    readerThread.start();
    System.out.println("Waiting for join..");
    writeWorker.join();
    System.out.println("Exit:"+ (System.currentTimeMillis() - startTime));
}

}

有两个线程:一个用于从结果集中获取行,另一个用于写入字符串值。测得的加载速度约为 10Mb/s,就我而言,我需要将其速度提高 10 倍。 Profiler 显示最耗时的方法是

oracle.jdbc.driver.OracleResultSetImpl.getString()

and

oracle.net.ns.Packet.receive()

您有什么想法如何使 jdbc 更快地加载数据吗? 任何关于查询优化、字符串加载优化、调整 JDBC 驱动程序或使用另一个驱动程序、直接使用 oracle JDBC 实现、调整 Oracle 的想法都值得赞赏。

UPDATE:我将讨论结果整理并列出如下:

  1. 除了连接到 Oracle 数据库之外,我无法访问 DBMS 服务器,并且服务器无法连接到任何外部资源。无法应用任何使用服务器或远程文件系统的转储和提取实用程序,也无法在服务器上安装和使用任何外部 java 或 PL/SQL 例程。仅用于执行查询的连接 - 仅此而已。

  2. 我使用了探查器并挖掘了 Oracle JDBC 驱动程序。我发现最昂贵的操作是读取数据,即 Socket.read()。所有字符串字段都表示为一个字符数组,对性能几乎没有影响。一般来说,我使用探查器检查了整个应用程序,并且 Socket.read() 绝对是最昂贵的操作。提取字段、构建字符串、写入数据几乎不消耗任何资源。问题仅在于读取数据。

  3. 服务器端数据表示的任何优化都不会产生实际效果。连接字符串和转换时间戳不会影响性能。

  4. 应用程序被重写为具有多个读取器线程,这些线程将准备好的数据放入写入器队列中。每个线程都有自己的连接,没有使用池,因为它们会减慢提取速度(我使用了oracle推荐的UCP池,它消耗了大约10%的执行时间,所以我放弃了)。结果集 fetchSize 也有所增加,因为从默认值 (10) 切换到 50000 可带来高达 50% 的性能增长。

  5. 我测试了多线程版本如何与 4 个读取线程配合使用,发现增加读取器数量只会减慢提取速度。 我尝试启动 2 个实例,每个实例都有两个读取器,并且都与单个实例同时工作,即双数据提取需要与单实例相同的时间。不知道为什么会发生这种情况,但看起来 oracle 驱动程序有一些性能限制。具有 4 个独立连接的应用程序比具有 2 个连接的 2 个应用程序实例运行速度慢。 (探查器用于确保驱动程序的 Socket.read() 仍然是主要问题,所有其他部分在多线程模式下工作正常)。

  6. 我尝试使用 SAS 获取所有数据,它执行相同提取的速度比 JDBC 快 2 倍,两者都使用与 Oracle 的单一连接,并且不能使用任何转储操作。 Oracle 确保 JDBC 瘦驱动程序与本机驱动程序一样快。

也许 Oracle 有另一种方法可以通过 ODBC 或其他方式快速提取到远程主机?


假设您已经检查了基本的网络内容,例如接口、防火墙、代理以及数据库服务器的硬件元素。

选项1 :

代替 :

Class.forName("oracle.jdbc.OracleDriver");
Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@//xxx.xxx.xxx.xxx:1521/orcl", "user", "pass");

尝试使用:

OracleDataSource ods = new OracleDataSource();
java.util.Properties prop = new java.util.Properties();
prop.setProperty("MinLimit", "2");
prop.setProperty("MaxLimit", "10");
String url = "jdbc:oracle:oci8:@//xxx.xxx.xxx.xxx:1521/orcl";
ods.setURL(url);
ods.setUser("USER");
ods.setPassword("PWD");
ods.setConnectionCachingEnabled(true);
ods.setConnectionCacheProperties (prop);
ods.setConnectionCacheName("ImplicitCache01");

更多细节here http://docs.oracle.com/cd/B19306_01/java.102/b14355/concache.htm

选项 2:获取大小

正如斯蒂芬强烈指出的那样,fetchsize 似乎太大了。

并且,对于 500,000 的获取大小,您的 -Xms 和 -Xmx 是多少。另外,在分析器中,最大堆大小是多少?

选项 3:数据库

  • 检查索引和查询计划src_schema.big_table_view

  • 这是一个工具还是一个应用系统。如果只是一个工具,你可以 基于数据库系统添加并行度、索引提示、分区等 能力

选项 4:线程

Say n

你可以开始了n写入器的线程,每个线程都配置为处理某个存储桶,例如thread1 处理 0 到 10000,写入n不同的文件,一旦所有线程完成,后连接,最好使用低级操作系统命令将文件合并在一起。

也就是说,所有这些都不应该是像现在这样的预定义代码。'n'并且桶应该在运行时计算。创建超过系统支持的线程数量只会搞砸。

选项 5:

代替

select * from src_schema.big_table_view

你可以使用

SELECT column1||CHR(9)||column2||CHR(9).....||columnN FROM src_schema.big_table_view

这可以避免创建 500000StringBuilders and Strings。 (假设不涉及其他复杂的格式)。 CHR(9) 是制表符。

选项 6:

同时,您还可以向 DBA 检查是否存在任何数据库系统问题,并提出 SR甲骨文支持 https://support.oracle.com.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

以极高的速度获取行 的相关文章

  • javax.naming.NameNotFoundException

    我正在 JBoss 5 容器中运行 ejb 示例 我正在使用一个例子从这里开始 第一部分 http www roseindia net jboss jboss 3 2 shtml 在示例中 我在 JBoss 中部署了 bean 并在 Tom
  • Lambda 表达式更慢?

    我有下面这段代码 PriorityQueue
  • 我如何通过代码在 Anylogic 中创建路径空间标记元素

    我在anyloigic方面完全是菜鸟 现在我正在尝试通过代码创建简单的网络 具有两个点节点的网络 以及链接这些节点的路径 遇到一些问题 当我运行模型时 控制台显示 使用初始化 方法 但我已经知道 初始化方法在较低版本中已被弃用 我使用的是8
  • 当目标是属性时,@Throws 不起作用

    在看的同时这个问题 https stackoverflow com q 47737288 7366707 我注意到申请 Throws to a get or setuse site 没有影响 此外 唯一有效的目标 for Throws ar
  • 具有 JPA、PostgreSQL 和 NULL 值的 JodaTime

    我试图将 JPA 的 JodaTime DateTime 字段保留到 PostgreSQL 但遇到了指向数据库 NULL 值的空指针的问题 我正在使用 NetBeans 7 beta 2 IDE 持久性实现是 EclipseLink 2 2
  • 设置 MetaspaceSize 的指南 - java 8

    64 位服务器的 MetaspaceSize 默认值是多少 我在官方文档中没有找到它 我观察到 在服务器 JVM 进程中 GC 频率有时会变高并持续增长 如果我重新启动服务几次 它就会恢复稳定 我认为这是由于 JRE 升级造成的 JVM 堆
  • Java SWT 用户输入验证

    在 SWT 中进行用户输入验证时 Java 约定是什么 我读到有 FieldEditors 它们是非常方便的字段 但遗憾的是仅适用于首选项和对话框 我还了解到有一个 IValidator 接口 但它经常与数据绑定一起使用 就我而言 我的大多
  • Android 3.1 USB 主机 - BroadcastReceiver 未收到 USB_DEVICE_ATTACHED

    我经历过USB 主机的描述和示例位于developer android com http developer android com guide topics usb host html检测连接和分离的 USB 设备 如果我在清单文件中使用
  • Spring Data (JPA) 多个存储库,没有很多类

    在我当前的项目中 我使用 Spring Data JPA 并且有 20 多个 Entity类 我想为它们创建存储库 但创建另一个类 每个类适用于任何模型 Repository注释似乎是某种矫枉过正和大量 重复 代码 所有存储库类将如下所示
  • 自动检测log4j静态初始化错误的方法

    请注意 这更像是 Bash 问题 而不是 Java 问题 请参阅下面的注释 在每个类中配置log4j时 我们执行以下操作 public class Example private static final Logger log Logger
  • 如何在生产中安全地更改会话 cookie 域或名称?

    我们最近意识到我们的会话 cookie 正在被写入我们网站的完全限定域名 www myapp com 例如 MYAPPCOOKIE 79D5DB83 domain www myapp com 我们希望将其切换为可以跨子域共享的cookie
  • 如果在构造函数中使用 super 调用重写方法会发生什么

    有两个班级Super1 and Sub1 超1级 public class Super1 Super1 this printThree public void printThree System out println Print Thre
  • 是否可以从 JBoss 容器中部署的所有 .war 文件中读取属性文件

    我已成功将 war 部署到 Jboss Web 容器 其中包含并读取位于 META INF groupid dir artifactid dir 下的 pom properties 为了访问该文件 我在同一 war 中的 JSP 中使用了以
  • 如何在 Google 地图中创建自定义地图?

    我正在尝试创建一个包含我家地图的 Google 地图应用程序 卧室 浴室 厨房等 使用 GPS 我会找到我现在在家里的位置 并尝试获取到我卧室的方向 步行距离 您可以使用Google的API来获取方向 我需要知道的是 如何添加我家的自定义地
  • 为什么ArrayList的非静态内部类SubList有一个成员变量“parent”?

    java util ArrayList SubList 是 java util ArrayList 的非静态内部类 这意味着它保存对其封闭类的引用 我们可以使用ArrayList this来访问java util ArrayList的成员
  • 注释处理工具<-检查有效注释

    I have ColumnMetadata index 1 ColumnMetadata index 2 ColumnMetadata index 3 我必须使用 APT 检查索引号是否唯一 我不知道该怎么做 我看不懂教程 一般我在网上找资
  • JAXB 枚举字段未序列化

    我有以下课程 package dictionary import java io Serializable import java util Objects import javax xml bind annotation XmlEleme
  • 数据库“key/ID”设计思想、代理键、主键等

    因此 我最近看到多次提到代理键 但我不太确定它是什么以及它与主键有何不同 我总是假设 ID 是表中的主键 如下所示 Users ID Guid FirstName Text LastName Text SSN Int 然而 维基百科将代理键
  • 如何比较表中最后一个和倒数第二个条目的值?

    我在 Oracle 中有一个名为quotes 的表 其中包含两列 date 和value 我想比较表中最后一个条目和倒数第二个条目的值 在此示例中 我想获取日期13 1 和 11 1在一行中以及每个日期的值之间的差异 10 5 5 报价表
  • 如何在服务器上获取球衣日志?

    我正在使用球衣进行 REST WS 如何在服务器端启用球衣日志 很长的故事 我收到客户端异常 但我在 tomcat 日志中没有看到任何内容 它甚至没有到达我的方法 由于堆栈跟踪显示 toReturnValue 它确实从服务器获取了一些内容

随机推荐

  • iOS10 SDK什么时候设置视图帧大小?

    多年来 我一直在 Swift 和 ObjC 中使用这种技术来制作圆形视图 view layer cornerRadius view frame size width 2 view clipsToBounds true 当 Storyboar
  • 串行版本 UID 有何用途? [复制]

    这个问题在这里已经有答案了 我正在创建一个 Java 应用程序 当创建一个与 ADT 一起使用的接口时 它发现需要将一个随机数初始化为 ID 号 public class StackFullException extends Runtime
  • DomIcon 的集群

    我正在尝试制作集群H map DomMarker 正在使用H map DomIcon与 HTML 代码 但原生的 Here Map 聚类不起作用 仅当我使用简单的H map Icon 但由于这被渲染为canvas图层 我无法使用自己的标记
  • MFC:如何捕获Web浏览器控件中的链接单击事件?

    我有一个带有 Web 控件的 MFC 应用程序 单击可单击链接时 它将使用 IE 打开 而不是默认浏览器 问题 有没有办法强制使用默认浏览器打开它 如果没有 我如何捕获链接单击事件 以便稍后可以操纵单击事件 谢谢 不 据我所知还没有 查看有
  • 在 Mathematica 中导入 Google Sketchup 模型

    Google 的 Sketchup 是一个漂亮 简单的 3D 对象建模器 此外 谷歌还拥有巨大的3D 对象仓库 http sketchup google com 3dwarehouse 因此 如果您在这方面不是特别有天赋 实际上您不必自己做
  • R 包“partykit”在 ctree_control 中未使用参数

    我想使用 partykit 包通过 ctree 和 cforest 构建分类树和森林 由于我的数据集包含 50000 行和 30 列 因此我想将 minsplit 设置为 150 将 minbucket 设置为 50 不幸的是 当我输入我的
  • 与 xgboost 并行线程?

    根据其文档 xgboost 有一个 n jobs 参数 但是 当我尝试设置 n jobs 时 出现此错误 TypeError init got an unexpected keyword argument n jobs 其他一些参数 如 r
  • OpenSSL 错误 - 无法获取本地颁发者证书

    我有一个简单的链设置 在这种情况下可以成功验证 openssl version OpenSSL 1 0 2m 2 Nov 2017 openssl verify CAfile chain pem cert pem cert pem OK 但
  • ember 数据验证的标准模式是什么? (无效状态,变成无效……)

    我已经为此苦苦挣扎了一段时间 让我们看看是否有人可以帮助我 尽管自述文件中没有明确说明 但 ember data 提供了一定程度的验证支持 您可以在代码和文档的某些部分看到 https github com emberjs data blo
  • 查找堆中元素的位置

    考虑以下元素列表 h 38 203 1 45 39 10 34 90 10 2 100 1 如果将其放入基于数组的堆中 它将按以下方式查找 import heapq heapq heapify h now we have a heap th
  • 如何使用 Javascript 在离开页面之前调用函数

    我想在离开页面之前执行一个函数 而不显示确认弹出窗口JavaScript仅有的 我已尝试使用下面的代码 但它不起作用或与onbeforeunload但它总是显示弹出窗口 var result test if window onbeforeu
  • 混合 C++11 std::thread 和 C 系统线程(即 pthreads)

    我正在编写一个多线程 C 程序 并希望使用多线程 C 库 该库希望我使用本机系统方法为其创建一些工作线程 并使用如下代码将控制权传递给其 run 函数 void system specific thread init ifdef WIN32
  • cpprestsdk:架构 x86_64 的未定义符号

    我已经访问了所有其他问题 但据我所知 没有一个问题是我的问题 在 MacBook Pro 16GB 内存 Intel Core I7 上运行 OS X El Capitan 10 11 6 我也运行过brew doctor 但没有发现任何会
  • ui-bootstrap 分页在初始化时重置当前页面

    我正在使用 ui bootstrap angular bootstrap 库中的分页指令 我在初始化时遇到问题 当我通过 url 导航到特定页面时 会出现问题 发生的情况是 我的控制器使用 stateParams 中的正确页面进行初始化 然
  • 如何在跨度内的 CSS 中创建所有浏览器兼容的悬挂缩进样式

    我唯一发现的是 hang text indent 3em margin left 3em 实现此目的的唯一方法是将文本放入段落中 这会导致那些非常难看的额外行 我宁愿把它们放在一个 span class hang span 类型的事物 我还
  • 使用 Karma / Jasmine 进行 Angular 8 测试 -> 角度路由中的 loadChildren 未覆盖 100% 代码覆盖率

    从 Angular 7 升级到 Angular 8 后 应用程序路由的 loadChildren 发生了重大变化 当这些问题得到修复并且所有测试都在运行时 我不再获得 100 的代码覆盖率 因为 loadChildren 不再是 字符串 而
  • 直接调用 vs 调用 vs 启动

    我在使用 Tivoli Workload Scheduler 运行批处理文件时遇到此问题 有一个第三方程序 假设它的名称是program exe 该批处理文件包含以下命令来调用program exe program exe param1 p
  • 多个力布局图,其中 d3 位于单独的 svg/div 中

    我在使用 d3 创建多个力布局图并从 json 文件读取数据时遇到问题 我使用 for 循环来迭代图表 为每个图表创建一个单独的 div 其中包含一个 svg 问题是 力布局仅应用于最后创建的布局 因此基本上其他布局仅在左上角显示一个点 我
  • UICollectionView 上的 register(_:forCellWithReuseIdentifier:) 有什么问题?

    我正在与一个UICollectionView As dequeueReusableCell withReuseIdentifier for 期望您必须使用以下方法注册类或 nib 文件register forCellWithReuseIde
  • 以极高的速度获取行

    我在 Oracle 中有一个非常大的表 数亿行 包含数字和字符串 我需要读取该表的所有内容 对其进行格式化并写入文件或任何其他资源 一般来说 我的解决方案如下所示 package my odp import java io Buffered