繁体   English   中英

通过java中的多个线程从数据库中读取

[英]Reading from Database through multiple threads in java

我正在使用 java 中的多个线程从 vertica 数据库中读取数据。 我有大约 2000 万条记录,并且我正在打开 5 个不同的线程,这些线程具有这样的选择查询......

start = threadnum;

while (start*20000<=totalRecords){

    select * from tableName order by colname limit 20000 offset start*20000.

    start +=5;

}

上面的查询将 20K 不同的记录分配给每个线程从 db 读取。 例如,第一个线程将读取前 20k 条记录,然后从 100 000 个位置开始读取 20K 条记录等

但我没有得到性能改进。 实际上,如果使用单个线程需要 x 秒来读取 2000 万条记录,那么每个线程从数据库中读取几乎需要 x 秒。 不应该比 x 秒有一些改进(期望 x/5 秒)吗?

任何人都可以查明出了什么问题吗?

除了您对多线程可以改善哪些情况以及哪些情况不能改善的理解之外,没有任何问题。

您的数据库可能位于单个磁盘上; 该磁盘使用单根数据线连接到主板; 如果数据库服务器在网络上,则它使用单根网线连接到该网络; 因此,所有数据在到达您的不同线程并被处理之前必须经过一条路径。

结果当然是非常糟糕的表现。

带回家的教训是这样的:

多线程永远无法改善来自同一设备的海量 I/O。

换句话说:当所有数据都来自单个顺序源时,处理数据的并行性永远不会提高性能。

如果你有 5 个不同的数据库存储在 5 个不同的磁盘上,那会更好。 (如果您还将这些磁盘连接到 5 个独立的 IDE 控制器,那效果会更好。)

我不会重复 Mike Nakis 所说的话,因为它是真实的并且解释清楚:

来自物理磁盘的 I/O 无法通过多线程改进

不过我想补充一点。

当您执行这样的查询时:

 select * from tableName order by colname limit 20000 offset start*20000.

从客户端,您可以处理可以通过使用多个线程来改进的查询结果。

但从数据库方面来看,您无法处理查询,而 Vertica 数据库可能旨在通过根据机器可能性执行并行任务来执行您的查询。

因此,从客户端您可以将查询的执行拆分为一个、两个或三个并行线程,它最终不应该改变很多事情,因为专业数据库旨在根据接收到的请求数量和机器优化响应时间可能性。

不,你不应该得到 x/5 秒。 您没有考虑在相同的时间内获得 5 倍的记录数这一事实。 这是关于吞吐量,而不是时间。

在我看来,以下是一个很好的解决方案。 它可以帮助我们流式传输和处理数百万条记录,而无需太多内存和处理开销。

PreparedStatement pstmt = conn.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
pstmt.setFetchSize(Integer.MIN_VALUE);
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
    // Do the thing
}

使用OFFSET x LIMIT 20000将导致一次又一次地执行相同的查询。 对于 2000 万条记录和每次执行 20K 条记录,查询将执行 1000 次。 OFFSET 0 LIMIT 20000会表现良好,但OFFSET 19980000 LIMIT 20000本身会花费很多时间。 由于查询将被完全执行,然后从顶部开始,它将不得不忽略 19980000 条记录并给出最后的 20000 条记录。

但是使用ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY选项并将获取大小设置为Integer.MIN_VALUE将导致查询仅执行一次,并且记录将分块流式传输,并且可以在单个线程中处理。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM