896cf3b425447a7157ac45b1574e67d3aa2d43ad
\346\225\260\346\215\256\345\272\223\351\205\215\347\275\256\350\214\203\344\276\213\346\261\207\346\200\273.md
| ... | ... | @@ -30,6 +30,8 @@ keepAlive=true |
| 30 | 30 | ``` |
| 31 | 31 | |
| 32 | 32 | ## 二 Oracle 配置范例 |
| 33 | +**注意:在数据量大的情况下,oracle必须配置:defaultRowPrefetch=1000,否则会有性能问题.** |
|
| 34 | +connectionProperties:defaultRowPrefetch=1000 |
|
| 33 | 35 | |
| 34 | 36 | #### 数据库配置(文件dbcp.properties)如下 |
| 35 | 37 | |
| ... | ... | @@ -53,9 +55,59 @@ testOnReturn=false |
| 53 | 55 | testWhileIdle=true |
| 54 | 56 | poolPreparedStatements: true |
| 55 | 57 | maxOpenPreparedStatements: 20 |
| 58 | +connectionProperties:defaultRowPrefetch=1000 |
|
| 56 | 59 | |
| 57 | 60 | ``` |
| 58 | 61 | |
| 62 | +### Oracle不设置fetchSize 性能瓶颈定位 |
|
| 63 | + |
|
| 64 | +``` |
|
| 65 | +`---[3460.7457ms] com.sie.snest.engine.db.relationdb.RelationDBAccessor:fetchMap() |
|
| 66 | + +---[1.07% 37.13ms] readMap() # 5995 次调用,单次平均 0.0062ms(很快) |
|
| 67 | + `---[97.90% 3388.18ms] scroll() # 5995 次调用,单次平均 0.565ms(很慢) |
|
| 68 | +``` |
|
| 69 | + |
|
| 70 | +- **`readMap()` 总耗时仅 37ms**(占比 1.07%),说明**行数据转换逻辑本身没有问题**,不需要优化 `ResultSetMetaData` 缓存等。 |
|
| 71 | +- **`scroll()` 总耗时高达 3388ms**(占比 97.9%),该方法内部调用 `resultSet.next()`,这是**从数据库服务器逐行拉取数据的网络 I/O 操作**。 |
|
| 72 | + |
|
| 73 | +### 根本原因 |
|
| 74 | + |
|
| 75 | +**JDBC 默认的 `fetchSize` 太小**(通常为 10),导致: |
|
| 76 | +- 数据库游标已打开,但数据仍驻留在数据库端。 |
|
| 77 | +- 每次 `resultSet.next()` 只取一行,需要 **5995 次网络往返**。 |
|
| 78 | +- 假设单次往返(含数据解析)约 0.56ms,总耗时 = 5995 × 0.56ms ≈ 3.3 秒。 |
|
| 79 | + |
|
| 80 | +### 优化方案(单一有效手段) |
|
| 81 | + |
|
| 82 | +**设置合理的 `fetchSize`**,让一次网络往返拉取多行数据。 |
|
| 83 | + |
|
| 84 | +### 方法一:修改框架代码(推荐) |
|
| 85 | + |
|
| 86 | +在 `RelationDBAccessor` 执行查询后、获取结果集前,增加设置: |
|
| 87 | + |
|
| 88 | +```java |
|
| 89 | +// 在 doExecute 方法中,创建 statement 后 |
|
| 90 | +statement.setFetchSize(1000); // 或 2000,根据单行数据大小调整 |
|
| 91 | +``` |
|
| 92 | + |
|
| 93 | +### 方法二:dbcp.properties connectionProperties添加:defaultRowPrefetch=1000 |
|
| 94 | +```java |
|
| 95 | +connectionProperties:defaultRowPrefetch=1000 |
|
| 96 | +``` |
|
| 97 | + |
|
| 98 | +### 方法三:全局 JDBC 参数(部分数据库支持) |
|
| 99 | + |
|
| 100 | +- **MySQL**:在 JDBC URL 添加 `defaultFetchSize=1000` |
|
| 101 | +- **Oracle**:设置 `oracle.jdbc.defaultRowPrefetch=1000` |
|
| 102 | +- **PostgreSQL**:连接参数 `defaultRowFetchSize=1000` |
|
| 103 | + |
|
| 104 | + |
|
| 105 | +### 总结 |
|
| 106 | + |
|
| 107 | +- **问题**:`scroll()` 中的 `ResultSet.next()` 因默认 fetchSize 太小导致 6000 次网络往返。 |
|
| 108 | +- **解决**:设置 `fetchSize` 为 1000~2000,**总耗时可从 3.4 秒降至 10 毫秒以内**。 |
|
| 109 | +- **无需优化**:`readMap()` 性能良好,不用改动。 |
|
| 110 | +- |
|
| 59 | 111 | |
| 60 | 112 | ## 三 PostgreSQL 配置范例 |
| 61 | 113 |