JDBC多线程查询结果汇总

假设单线程查询SQL耗时1S,那么开启两个线程查询SQL理想情况下也是1S多点才对,机器是4核,但是目前结果近乎2倍显然有异;

暂且不考虑从线程池获取连接,任务线程核心代码如下:

@Override
public void run() {
    long s = System.currentTimeMillis();
    System.out.println(Thread.currentThread().getName() + "准备执行");
    try (Connection connection = DBUtils.openConnection();
         PreparedStatement preparedStatement = connection.prepareStatement(querySql);
         ResultSet resultSet = preparedStatement.executeQuery()) {
        long e = System.currentTimeMillis();
        System.out.println(Thread.currentThread().getName() + "执行耗时:" + (e - s));

    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        latch.countDown();
    }
}

目的是分表查询采用多线程,使用CountDownLatch,结果汇总,提交任务代码如下:

CountDownLatch countDownLatch = new CountDownLatch(TABLE_SIZE);
ExecutorService executor = Executors.newFixedThreadPool(TABLE_SIZE);
List<String> names = new LinkedList<>();
long s = System.currentTimeMillis();
System.out.println("获取数据库连接成功,准备执行SQL...");

try {
    for (int i = 0; i < TABLE_SIZE; i++) {
        Task task = new Task(countDownLatch, names, PRE_SQL + i);
        executor.execute(task);
    }
    countDownLatch.await();
    executor.shutdownNow();
} catch (InterruptedException e) {
    e.printStackTrace();
}

long e = System.currentTimeMillis();
System.out.println("总耗时:" + (e - s) + "ms");

当指定1个任务时,控制台输出:

获取数据库连接成功,准备执行SQL...
pool-1-thread-1准备执行
pool-1-thread-1执行耗时:708
总耗时:708ms

当指定2个任务时,控制台输出:

获取数据库连接成功,准备执行SQL...
pool-1-thread-1准备执行
pool-1-thread-2准备执行
pool-1-thread-2执行耗时:2054
pool-1-thread-1执行耗时:2055
总耗时:2057ms

当指定4个任务时,控制台输出:

获取数据库连接成功,准备执行SQL...
pool-1-thread-2准备执行
pool-1-thread-3准备执行
pool-1-thread-1准备执行
pool-1-thread-4准备执行
pool-1-thread-3执行耗时:3189
pool-1-thread-1执行耗时:3203
pool-1-thread-2执行耗时:3241
pool-1-thread-4执行耗时:3245
总耗时:3248ms

在程序运行期间查看mysql,show processlist;

| 136 | root | localhost:50225 | test | Query   |     1 | Sending data | SELECT SQL_NO_CACHE `id`, `name` FROM test_3 |
| 135 | root | localhost:50224 | test | Query   |     1 | Sending data | SELECT SQL_NO_CACHE `id`, `name` FROM test_1 |
| 138 | root | localhost:50227 | test | Query   |     1 | Sending data | SELECT SQL_NO_CACHE `id`, `name` FROM test_0 |
| 137 | root | localhost:50226 | test | Query   |     1 | Sending data | SELECT SQL_NO_CACHE `id`, `name` FROM test_2 |

然后SQL状态就变成了Writing to net,不知道是否正常,对Mysql不是很懂。

我也试过单线程for循环6次,耗时出入不大。

单条SQL执行差不多在1S左右,现在4条SQL同时执行,并没有在1S多就返回结果,而是在3S多同时结束,那么这里的问题到底是什么原因导致的呢?

阅读 7.7k
3 个回答

Writing to net

The server is writing a packet to the network. This state is called Sending to client as of MySQL 5.7.8.

ref: https://dev.mysql.com/doc/ref...

本地select 超过1S,推测你每次select出的数据集比较大,本地的packet设置得过小

在Mysql执行下

show global variables like "max_allowed_packet"

解决方案:

  1. 降低每次查询出的结果集
  2. 增大max_allowed_packet

貌似和 这个问题 是同一个环境?
数据量太大,网络带宽打满了吧

如果瓶颈在带宽或数据库处理能力,多线程就不能解决这个性能问题

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题