经常听人说, 数据库的 IO 性能不佳, 但说归说, 并没有感性认识. 我们现在就来实际测试一下, 常用的 Oracle 和 MySQL 的 JDBC 读取性能如何.
之所以测试 JDBC, 是因为大部分应用是 JAVA 写的, 也就只能用 JDBC 来访问数据. 这里仅测试用 JDBC 读出数据, 并产生成 Java 的记录对象(毕竟到了这一步才能在应用中使用), 不作任何计算.
1. 数据来源
使用 TPCH 生成的数据, 选用其中的 customer 表来做测试, 数据记录为 3000 万行, 8 个字段. 它生成的原始文本文件名为 customer.tbl, 文件大小为 4.9G. 利用数据库提供的数据导入工具将此文件数据导入到 Oracle 和 MySQL 的数据表中.
2. 测试环境
在一台 Intel 服务器上完成测试, 2 个 Intel2670 CPU, 主频 2.6G, 共 16 核, 内存 64G. 数据库表数据及文本文件均存储在同一块 SSD 硬盘上.
所有测试均在服务器本机上完成, 没有消耗网络传输时间.
3. 数据库读数测试
通过 Oracle 提供的 JDBC 接口, 用 SQL 语句执行数据读取.
Java 写起来麻烦, 用 SPL 脚本执行测试:
MySQL 的测试代码类似, 不再赘述.
测试结果(时间单位: 秒)
第二次可能由于操作系统有了硬盘缓存, 所以更快. 因为我们主要是为了测试 JDBC 的读取时间, 所以就以第二次为准, 减少数据库本身从硬盘读数的影响. 每秒读出行数也是按第二次时间来计算的, 也就是说, Oracle 每秒能读出 10 万行多数据, MySQL 大概接近 8 万行. 当然这个值和表的字段数及类型都有关(customer 表有 8 个字段), 只是一种参考.
4. 文本文件对比
只从上面的数据量还没有太多感性认识, 我们再读一下文本文件来对比. 办法是一样的, 从文件中读出数据, 并解析出记录, 不作任何计算.
编写如下 SPL 脚本执行测试:
测试结果是 42 秒!
这意味着, 读取文本要比读取 Oracle 快 281/42=6.69 倍, 比 MySQL 要快 381/42=9.07 倍!
我们知道, 文本解析是个非常麻烦的事情, 但即使这样, 从文本文件读取数据还是远远快于从数据库中读数. Oracle 和 MySQL 的 IO 实在是太慢了!
5. 二进制方式
我们进一步再看使用二进制方式的存储格式的读取性能, 并和文本比对.
为了对比明显, 这次换一个更大的表, 用 TPCH 中的 orders 表, 有 3 亿行数据, 9 个字段.
文本读取的代码和上面类似, 读取时间测试为 438 秒.
然后, 我们将这个文本文件转换成 SPL 组表, 再写代码测试:
测试结果是 164 秒, 大概仅仅是文本读取的三分之一.
这是情理之中的事情, 因为二进制数据不再需要解析, 可以直接产生对象, 计算量少了很多, 因而要更快.
需要说明的是, 组表文件虽然采用列存格式, 但在这里读出了所有列, 并没有比文本少取任何内容, 没有占列存的便宜. 事实上, 因为读所有列, 使用列存还会吃点亏, 如果采用 SPL 集文件 (一种行存格式) 还会更快.
6. 并行提速
从文件中取数还很容易实现并行, 文本和组表都容易写出并行程序. 还是用上面的 orders 表为例来测试, 使用 4 线程取数.
文本取数代码:
组表取数代码:
用 SPL 很容易实现数据分段和并行计算.
测试结果为:
文本 119 秒
组表 43 秒
与串行相比, 接近了线性提升, 将 CPU 的多核充分利用起来了.
数据库中的数据则不容易简单地实施分段并行, 需要用 WHERE 条件去拼, 结果很难说清到底是并行不力还是 WHERE 执行损失太多, 测试结果的参考意义就打折扣了, 这里就不再做了.
7. 结论
数据库 (Oracle 和 MySQL) 的 JDBC 性能非常非常差! 比文本文件还要差 5 倍以上. 而采用二进制数据时, 会比文本再提高 3 倍的读取性能. 也就是说, 合理格式的二进制文件会比数据库有 15 倍以上的优势. 再考虑到并行因素, 比数据库快出几十上百倍也是完全可能的.
在关注性能且数据量较大时, 千万不要把数据读出数据库计算!
如果实在需要读出后再计算(有时 SQL 很难写出复杂的过程计算), 就不要再用数据库存储了(大数据都是历史, 基本也不再改了, 可以事先读出), 用文本都比数据库强, 用二进制当然更好(推荐使用 SPL 组表, 哈哈). 切不要把时间浪费在读数这种非计算任务上了.
来源: http://database.51cto.com/art/201909/603313.htm