Benchmark
基准测试的源代码在此,使用H2的内存数据库,无需任何环境准备即可直接运行。
报告
每秒操作次数
- 横坐标表示每次从数据库中查询到的数据对象的数量。
- 纵坐标表示每秒操作次数。
- 图表
- 数据
Framework | Data count | Ops/s |
---|---|---|
JDBC(ColIndex) | 10 | 564001 |
JDBC(ColIndex) | 20 | 480692 |
JDBC(ColIndex) | 50 | 232401 |
JDBC(ColIndex) | 100 | 134663 |
JDBC(ColIndex) | 200 | 71072 |
JDBC(ColIndex) | 500 | 30751 |
JDBC(ColIndex) | 1000 | 14681 |
JDBC(ColName) | 10 | 340041 |
JDBC(ColName) | 20 | 194774 |
JDBC(ColName) | 50 | 125967 |
JDBC(ColName) | 100 | 55368 |
JDBC(ColName) | 200 | 38823 |
JDBC(ColName) | 500 | 16254 |
JDBC(ColName) | 1000 | 8157 |
Jimmer(Java) | 10 | 234769 |
Jimmer(Java) | 20 | 135347 |
Jimmer(Java) | 50 | 70747 |
Jimmer(Java) | 100 | 35901 |
Jimmer(Java) | 200 | 18585 |
Jimmer(Java) | 500 | 7661 |
Jimmer(Java) | 1000 | 3759 |
Jimmer(Kotlin) | 10 | 231853 |
Jimmer(Kotlin) | 20 | 133594 |
Jimmer(Kotlin) | 50 | 61121 |
Jimmer(Kotlin) | 100 | 27805 |
Jimmer(Kotlin) | 200 | 16830 |
Jimmer(Kotlin) | 500 | 6920 |
Jimmer(Kotlin) | 1000 | 3486 |
MyBatis | 10 | 77973 |
MyBatis | 20 | 43833 |
MyBatis | 50 | 20453 |
MyBatis | 100 | 10489 |
MyBatis | 200 | 5147 |
MyBatis | 500 | 1922 |
MyBatis | 1000 | 1059 |
Exposed | 10 | 96617 |
Exposed | 20 | 69563 |
Exposed | 50 | 34146 |
Exposed | 100 | 19736 |
Exposed | 200 | 10249 |
Exposed | 500 | 4261 |
Exposed | 1000 | 2182 |
JPA(Hibernate) | 10 | 103156 |
JPA(Hibernate) | 20 | 60658 |
JPA(Hibernate) | 50 | 26730 |
JPA(Hibernate) | 100 | 13504 |
JPA(Hibernate) | 200 | 6850 |
JPA(Hibernate) | 500 | 2540 |
JPA(Hibernate) | 1000 | 1437 |
JPA(EclipseLink) | 10 | 63772 |
JPA(EclipseLink) | 20 | 33637 |
JPA(EclipseLink) | 50 | 13525 |
JPA(EclipseLink) | 100 | 6815 |
JPA(EclipseLink) | 200 | 3232 |
JPA(EclipseLink) | 500 | 1361 |
JPA(EclipseLink) | 1000 | 666 |
JOOQ | 10 | 57410 |
JOOQ | 20 | 35126 |
JOOQ | 50 | 14441 |
JOOQ | 100 | 9955 |
JOOQ | 200 | 3738 |
JOOQ | 500 | 1689 |
JOOQ | 1000 | 994 |
Nutz | 10 | 82881 |
Nutz | 20 | 48008 |
Nutz | 50 | 17310 |
Nutz | 100 | 8570 |
Nutz | 200 | 5124 |
Nutz | 500 | 1892 |
Nutz | 1000 | 964 |
ObjectiveSQL | 10 | 59701 |
ObjectiveSQL | 20 | 29487 |
ObjectiveSQL | 50 | 12662 |
ObjectiveSQL | 100 | 6795 |
ObjectiveSQL | 200 | 3419 |
ObjectiveSQL | 500 | 1356 |
ObjectiveSQL | 1000 | 599 |
Spring Data JDBC | 10 | 20612 |
Spring Data JDBC | 20 | 10123 |
Spring Data JDBC | 50 | 4029 |
Spring Data JDBC | 100 | 1984 |
Spring Data JDBC | 200 | 1079 |
Spring Data JDBC | 500 | 412 |
Spring Data JDBC | 1000 | 227 |
Ktorm | 10 | 17717 |
Ktorm | 20 | 10214 |
Ktorm | 50 | 4182 |
Ktorm | 100 | 2041 |
Ktorm | 200 | 1067 |
Ktorm | 500 | 356 |
Ktorm | 1000 | 181 |
每次操作耗时
- 横坐标表示每次从数据库中查询到的数据对象的数量。
- 纵坐标表示每次操作耗时(微秒)。
- 图表
- 数据
Framework | Data count | Time(μs) |
---|---|---|
JDBC(ColIndex) | 10 | 2 |
JDBC(ColIndex) | 20 | 2 |
JDBC(ColIndex) | 50 | 4 |
JDBC(ColIndex) | 100 | 7 |
JDBC(ColIndex) | 200 | 14 |
JDBC(ColIndex) | 500 | 33 |
JDBC(ColIndex) | 1000 | 68 |
JDBC(ColName) | 10 | 3 |
JDBC(ColName) | 20 | 5 |
JDBC(ColName) | 50 | 8 |
JDBC(ColName) | 100 | 18 |
JDBC(ColName) | 200 | 26 |
JDBC(ColName) | 500 | 62 |
JDBC(ColName) | 1000 | 123 |
Jimmer(Java) | 10 | 4 |
Jimmer(Java) | 20 | 7 |
Jimmer(Java) | 50 | 14 |
Jimmer(Java) | 100 | 28 |
Jimmer(Java) | 200 | 54 |
Jimmer(Java) | 500 | 131 |
Jimmer(Java) | 1000 | 266 |
Jimmer(Kotlin) | 10 | 4 |
Jimmer(Kotlin) | 20 | 7 |
Jimmer(Kotlin) | 50 | 16 |
Jimmer(Kotlin) | 100 | 36 |
Jimmer(Kotlin) | 200 | 59 |
Jimmer(Kotlin) | 500 | 145 |
Jimmer(Kotlin) | 1000 | 287 |
MyBatis | 10 | 13 |
MyBatis | 20 | 23 |
MyBatis | 50 | 49 |
MyBatis | 100 | 95 |
MyBatis | 200 | 194 |
MyBatis | 500 | 520 |
MyBatis | 1000 | 944 |
Exposed | 10 | 10 |
Exposed | 20 | 14 |
Exposed | 50 | 29 |
Exposed | 100 | 51 |
Exposed | 200 | 98 |
Exposed | 500 | 235 |
Exposed | 1000 | 458 |
JPA(Hibernate) | 10 | 10 |
JPA(Hibernate) | 20 | 16 |
JPA(Hibernate) | 50 | 37 |
JPA(Hibernate) | 100 | 74 |
JPA(Hibernate) | 200 | 146 |
JPA(Hibernate) | 500 | 394 |
JPA(Hibernate) | 1000 | 696 |
JPA(EclipseLink) | 10 | 16 |
JPA(EclipseLink) | 20 | 30 |
JPA(EclipseLink) | 50 | 74 |
JPA(EclipseLink) | 100 | 147 |
JPA(EclipseLink) | 200 | 309 |
JPA(EclipseLink) | 500 | 735 |
JPA(EclipseLink) | 1000 | 1501 |
JOOQ | 10 | 17 |
JOOQ | 20 | 28 |
JOOQ | 50 | 69 |
JOOQ | 100 | 100 |
JOOQ | 200 | 268 |
JOOQ | 500 | 592 |
JOOQ | 1000 | 1006 |
Nutz | 10 | 12 |
Nutz | 20 | 21 |
Nutz | 50 | 58 |
Nutz | 100 | 117 |
Nutz | 200 | 195 |
Nutz | 500 | 529 |
Nutz | 1000 | 1038 |
ObjectiveSQL | 10 | 17 |
ObjectiveSQL | 20 | 34 |
ObjectiveSQL | 50 | 79 |
ObjectiveSQL | 100 | 147 |
ObjectiveSQL | 200 | 292 |
ObjectiveSQL | 500 | 738 |
ObjectiveSQL | 1000 | 1671 |
Spring Data JDBC | 10 | 49 |
Spring Data JDBC | 20 | 99 |
Spring Data JDBC | 50 | 248 |
Spring Data JDBC | 100 | 504 |
Spring Data JDBC | 200 | 927 |
Spring Data JDBC | 500 | 2429 |
Spring Data JDBC | 1000 | 4413 |
Ktorm | 10 | 56 |
Ktorm | 20 | 98 |
Ktorm | 50 | 239 |
Ktorm | 100 | 490 |
Ktorm | 200 | 937 |
Ktorm | 500 | 2809 |
Ktorm | 1000 | 5539 |
备注
由于Spring移除了对OpenJPA的支持,本基准测试不包含JPA(OpenJPA)
实现原则
所有框架禁用缓存
所有框架关闭日志
所有框架每次都打开和关闭连接/会话,不做共享;靠连接池保证性能。
接入Spring的连接管理机制。因不同框架API不同,实现方法略有不同。
- 有的使用DataSourceUtils的getConnection和releaseConnection
- 有的使用TransactionAwareDataSourceProxy
但最终效果都一样
不使用事务
Exposed
比较特殊,其API强制要求事务,给予假的实现。使用嵌入的H2内数据库,尽可能压缩数据库的消耗,凸显ORM本身的性能,即映射的性能。
价值
一种常见的观点:ORM本身的性能不重要,实际项目中,数据库并非有内嵌内存数据库,所以ORM本身耗时相对于数据库耗时可忽略不计。
反驳:Java19发布后,支持虚拟线程。ORM能尽快完成映射,可以让JVM去调度更多的虚拟线程。