使用 jdbc 和 mysql 并行化查询是否值得?

Is it worth to parallelize queries with jdbc and mysql?

一个 jdbc "select" 语句需要 5 秒才能完成。 所以做 5 条语句需要 25 秒。

现在我尝试并行完成这项工作。 db 是 mysql with innodb。 我启动了 5 个线程并为每个线程提供了自己的数据库连接。但是全部完成还需要25秒?

注意我提供 java 足够的堆并且有 8 个内核但只有一个硬盘(也许只有一个硬盘是这里的瓶颈?)

这是开箱即用 mysql 的预期行为吗? 这是示例代码:

public void doWork(int n) {
        try (Connection conn = pool.getConnection();
             PreparedStatement stmt = conn.prepareStatement("select id from big_table where id between "+(n * 1000000)" and " +(n * 1000000 +1000000));
        ) { 
            try (ResultSet rs = stmt.executeQuery();) {
                while (rs.next()) {
                    Long itemId = rs.getLong("id");
                }
            }
        }
}

public void doWorkBatch() {
    for(int i=1;i<5;i++)
        doWork(i);
}

public void doWorkParrallel() {
    for(int i=1;i<5;i++)
        new Thread(()->doWork(i)).start();
    System.console().readLine();
}

(我不记得在哪里,但我读到标准 mysql 安装可以轻松地并行处理 1000 个连接)

并发执行可能会更快。您还应该考虑批量执行。

这取决于您系统中的瓶颈在哪里... 如果您的查询每次都花费几秒钟来建立与数据库的连接,而实际上只 运行 查询的一小部分,您会看到一个不错的改进。 但是,如果将时间花在 mysql、运行 实际查询上,您将不会看到太大的差异。

我要做的第一件事不是尝试并发执行,而是优化查询,可能会向您的表添加索引,等等。

如果有任何并行化空间,并发执行将有所帮助。在你的情况下,似乎没有并行化的空间,因为你有一个非常简单的查询,它执行大量数据的顺序读取,所以你的瓶颈可能是磁盘传输,然后是数据从服务器传输到客户.

当我们说 RDBMS 服务器每秒可以处理数千个请求时,我们通常是在谈论我们通常在 Web 应用程序中看到的那种请求,其中每个 SQL 查询都比您的稍微复杂一些,但会导致更小的磁盘读取(因此它们很可能在缓存中找到)和更小的数据传输(适合网页的内容。)

看看你的问题,多线程肯定会提高你的性能,因为即使我曾经通过完全按照你的想法将 4-5 小时的批处理作业转换为 7-10 分钟的作业,但你需要在设计时事先了解以下内容:-

1) 您需要考虑任务间依赖性,即任务在不同线程上执行。

2) 使用连接池是一个好兆头,因为在 Java 中创建数据库连接的过程很慢并且需要很长时间。

3) 每个线程都需要自己的 JDBC 连接。不能在线程之间共享连接,因为每个连接也是一个事务。

4) 将任务分成几个工作单元,每个单元做一项工作。

5) 特别针对您的情况,即使用 mysql。您使用哪个数据库引擎也会影响性能,因为 InnoDB 引擎使用行级锁定。这样,它将处理更高的流量。然而,(通常的)替代方案 (MyISAM) 不支持行级锁定,它使用 table 锁定。 我说的是这种情况如果另一个线程进入并想在第一个线程提交之前更新同一行怎么办。

6) 要提高 Java 数据库应用程序的性能,请使用 setAutoCommit(false) 进行 运行 查询。默认情况下,新 JDBC 连接的自动提交模式为 ON,这意味着每个单独的 SQL 语句都将在其自己的事务中执行。如果没有自动提交,您可以将 SQL 语句分组为逻辑事务,可以通过调用 commit() 或 rollback() 来提交或回滚。

你也可以查看专为批处理设计的springbatch。

希望对您有所帮助。