比较多线程和线程池,先保证写入量、成功标准和事务条件一致。2019年的这组MySQL插入记录,保留了有用的观察,也有不能直接横向比较的项目。

先把原始记录摆清楚

下表是当年的笔记自述,不是此次重新测量的结果;缺少机器、表结构、SQL、连接池与事务配置:

目标量方式当年记录
1万条单线程127709ms,约127.7秒
1万条普通10线程约7秒
1万条newCachedThreadPool约7秒
10万条普通10线程约59秒
10万条newCachedThreadPool约3万条后连接报错,约47秒即失败
10万条newFixedThreadPool(10)约63秒
100万条普通10线程实际约110万条,约11分10秒
100万条newFixedThreadPool(10)记录为约10分32秒

时间戳与手记耗时有取整差异,不能把这些近似数当作高精度基准。失败的3万条执行不是成功插入10万条的性能;110万与100万也不是相同工作量。

线程池的意义不只有一次总耗时

newCachedThreadPool会按需要创建并复用线程;newFixedThreadPool限制同时工作的线程数量,但使用共享无界队列,不意味着所有资源天然有界。Java 8 Executors

数据库连接数、获取连接等待、单条/批量写入、提交频率、索引维护与磁盘持久化,都可能成为主要成本。只看两种方案总时间接近,不能得出线程复用没有价值,也不能由连接报错断言MySQL服务已经崩溃。

连接异常还要区分连接池耗尽、超时、服务端限制和真正进程退出;保留原因链及服务端日志,不能以猜测代替诊断。

怎样设计更可比较的测量

在授权的隔离数据库中,固定数据集、表和索引、事务批次、连接池上限与成功行数,分别记录提交任务数、完成数、失败/重试及总用时。等待所有任务完成后再停止计时,不能只测提交循环。

比较时控制预热和重复次数,报告吞吐、波动和资源占用;另设停止条件,避免无界排队或大量重试压垮目标。这里没有提供会直接写入百万行的启动脚本,也没有执行压测。

LIKE不能一句话判断索引无效

当年还记录title查询约从1.3秒降到0.01秒,以及某些LIKE查询仍约1.3秒。缺少SQL与执行计划,不能归结为“LIKE不管有没有索引都慢”。

例如前缀匹配和前导通配符匹配可能具有不同的范围访问条件,仍受类型、排序规则和索引定义影响,应查看实际explain。MySQL范围优化

这组数据可以提醒我们怎样检查比较条件,不能成为“10线程一定更快”或线程池优劣的通用证明。