首批通过分布式安全可靠测评,为关键业务系统打造
OceanBase 的 Batch 执行
更新时间:2025-03-02 03:26
OceanBase 的 Batch 执行是什么?
当使用 JDBC 和 OceanBase 进行交互时,可以把多次请求放进一个组,从而进行一次网络传输完成多次请求,这被称为 Batch 执行,通常也被称为批处理。
为什么要使用 Batch 执行?
有时候会因为数据的一致性而使用 Batch 执行,但更多时候,使用 Batch 执行最大的好处是可以提升性能,这体现在几个方面:
- Batch 执行可以减少和数据库的交互次数。
- Batch 语句会被改写以提高性能。
- OceanBase 在收到 Batch 执行时可以做一些优化工作,进一步提升性能。
JDBC 中哪些 class/object 可以实现 Batch 执行?
无论使用 Statement 还是 PrepareStatement 都可以实现 Batch 执行。
使用 Batch 执行需要设置什么 JDBC 配置属性?
- 从功能上说,使用 Batch 执行必须要设置
rewriteBatchedStatements=TRUE。 - 从实现和行为上说,useServerPrepStmts 会决定 Batch 执行的不同行为。
- 从性能上说,cachePrepStmts,prepStmtCacheSize,prepStmtCacheSqlLimit,maxBatchTotalParamsNum 会对性能上有所帮助。
| 配置属性 | 默认值 | 说明 |
|---|---|---|
| allowMultiQueries | FALSE | 决定一条语句中是否可以用 ; 分割多个请求,Batch 执行并不依赖于这个属性,而仅仅依赖于 rewriteBatchedStatements。
注意
|
| rewriteBatchedStatements | FALSE | 决定 Batch 执行中是否会重写 INSERT 语句。对于 PrepareStatement 对象,会使用多个 VALUES 来拼接;对于 Statement 对象,会使用分号来拼接多个 INSERT 语句。 |
| useServerPrepStmts | FALSE | 决定是否使用 Server 端的 Prepared 语句,仅对 PrepareStatement 对象有效。
注意如果设置了 |
| cachePrepStmts | FALSE/TRUE | 决定 JDBC driver 是否缓存 Prepared 语句,针对 Client 端的 Prepared 语句和 server 端的 Prepared 语句,缓存的内容稍有不同。
注意
|
| prepStmtCacheSize | 25/250 | 如果开启了 cachePrepStmts,决定了可以缓存多少条 prepared statements。
注意
|
| prepStmtCacheSqlLimit | 256/2048 | 如果开启了 cachePrepStmts,决定了可以缓存最大的 SQL 是多大。
注意
|
| maxBatchTotalParamsNum | 30000 | 当使用 executeBatch,决定了最大可以拼接多少个参数。
注意
|
哪些 OceanBase 的配置项/变量和 Batch 执行有关?
如下配置项和 Batch 执行有关系
| 参数 | 默认值 | 范围 | 生效方式 | 含义 |
|---|---|---|---|---|
| ob_enable_batched_multi_statement | FALSE | 租户 | 动态 | 用于设置是否启用批处理多条语句的功能。开启这个参数同时也意味着:在 Batch 执行场景下,当 Client/Server 使用文本协议进行通许时,OceanBase 会对格式一致的多条 UPDATE 语句当成一条语句进行解析,并根据对应的参数和数据分布,生成 batch physical plan。 |
| _ob_enable_prepared_statement | FALSE | 集群 | 动态 | 表示是否可以使用 server 端的 Prepared 语句 |
| _enable_static_typing_engine | TRUE | 集群 | 动态 | 指定是否使用新的 SQL 引擎。新老的 SQL 引擎对于是否能处理 Batch UPDATE 有差别,老引擎只能处理包含全部主键的 Batch UPDATE,新引擎虽然能处理不包含全部主键的 Batch UPDATE,但需要在较新分支的 OceanBase V3.2 版本才能有这个能力。 |
| 变量 | 默认值 | 级别 | 含义 |
|---|---|---|---|
| _enable_dist_data_access_service | TRUE | session/global | 打开或者关闭 SQL 以 DAS 的方式执行,在 OceanBase V3.2 版本后的新 SQL 引擎中,如需要获得 Batch UPDATE 的优化能力,需要打开这个变量。 |
Statement 和 PrepareStatement 在行为和使用方法上有什么不同?
使用 Statement 对象
conn = DriverManager.getConnection(obUrl); conn.setAutoCommit(false); Statement stmt = conn.createStatement(); String SQL = "INSERT INTO test1 (c1, c2) VALUES (1, 'test11')"; stmt.addBatch(SQL); String SQL = "INSERT INTO test1 (c1, c2) VALUES (2, 'test12')"; stmt.addBatch(SQL); String SQL = "INSERT INTO test1 (c1, c2) VALUES (3, 'test13')"; stmt.addBatch(SQL); int[] count = stmt.executeBatch(); stmt.clearBatch(); conn.commit();使用 PrepareStatement 对象
conn = DriverManager.getConnection(obUrl); conn.setAutoCommit(false); String SQL = "INSERT INTO TEST1 (C1, C2) VALUES (?, ?)"; PreparedStatemen pstmt = conn.prepareStatement(SQL); int rowCount = 5, batchCount = 10; for (int k=1; k<=batchCount; k++) { for (int i=1; i<=rowCount; i++) { pstmt.setInt(1, (k*100+i)); pstmt.setString(2, "test value"); pstmt.addBatch(); } int[] count = pstmt.executeBatch(); pstmt.clearBatch(); } conn.commit(); pstmt.close();
下表列出使用 PrepareStatement 和 Statement 对象时,Batch 执行的不同行为,前提需要 rewriteBatchedStatements=TRUE 。
PrepareStatement:
useServerPrepStmts INSERT UPDATE 备注 TRUE 多条 INSERT 语句的 VALUES 会以多个 ?的形式拼接在一条 INSERT 语句的多个 VALUES 中,形如:INSERT INTO TEST1 VALUES (?), (?),...,(?)多条单独的 UPDATE 语句,其中的变量用 ?替代场景 1 FALSE 多条 INSERT 语句的 VALUES 会以多个具体值的形式拼接在一条 INSERT 语句的多个 VALUES 中,形如:INSERT INTO TEST1 VALUES (1), (2),...,(10) 多条单独的 UPDATE 语句用分号拼接在一起 场景 2 Statement:
useServerPrepStmts INSERT UPDATE 备注 TRUE 多条单独的 INSERT 语句用分号拼接在一起 多条单独的 UPDATE 语句用分号拼接在一起 场景 3 FALSE 多条单独的 INSERT 语句用分号拼接在一起 多条单独的 UPDATE 语句用分号拼接在一起 场景 4
OceanBase 的 Batch 执行有哪些类型?分别对请求的优化处理有哪些?
从语句角度看,OceanBase 的 Batch 执行针对 INSERT,UPDATE 和 DELETE 的处理是不同的,这从上表也可以看出,具体如下:
INSERT
在场景 1 中,OceanBase 服务器端会收到一次 INSERT 语句的 COM_STMT_PREPARE 请求(request_type=5)和 一次 INSERT 语句的 COM_STMT_EXECUTE 请求(request_type=6),从优化的角度看,有如下好处:
- 只需要发生两次通讯就完成了 INSERT 语句的 Batch 执行。
- PrepareStatement 天然的属性可以减少编译时间。
- 假设后续有更多的 executeBatch,且设置了合理的 cachePrepStmts 及相关参数,可以减少 prepare 请求(request_type=5)的次数,而只需要执行 execute 请求(request_type=6)。
在场景 2 中,OceanBase 服务器端会收到一次 INSERT 语句的 COM_QUERY 请求(request_type=2),从优化的角度看,有如下好处:
- 只需要发生一次通讯就完成了 INSERT 语句的 Batch 执行。
在场景 3 和 4 中,OceanBase 服务器端会收到一个由多条 INSERT 语句用分号拼接在一起的请求,并依次执行,所以也具有如下好处:
- 只需要发生一次通讯就完成了 INSERT 语句的 Batch 执行。
UPDATE
如果没有开启 ob_enable_batched_multi_statement,场景 1/2/3/4 的 UPDATE Batch 执行在 OceanBase server 端都会被依次执行,不会有特别的优化。
如果开启了 ob_enable_batched_multi_statement,那么对于场景 2/3/4 的 UPDATE Batch 执行,OceanBase server 端会对格式一致的多条 UPDATE 语句当成一条语句进行解析,并根据对应的参数和数据分布,生成 batch physical plan,这可以有效的提升 Batch UPDATE 执行的效率。但在使用这个功能上有几个注意事项:
- 在 OceanBase V3.1 版本中,仅当 UPDATE 的谓语中包含全部的主键时才能被优化;在 OceanBase V3.2 版本中,可以没有这个限制,但需要确保打开
_enable_dist_data_access_service变量并启用新 SQL 引擎_enable_static_typing_engine=TRUE。 - 同一批次的 UPDATE 中不能有相同的行。
- 需要开启显式事务。
DELETE
当前版本对于 Batch DELETE,都是依次执行。
如何在不同的场景下选择不同的配置?
如果可能,尽量选择较新版本的 oceanbase-client jar 包,如上表所示,1.x 和 2.x 的 jar 包行为有些许不同,1.1.9 版本的 jar 包在 Oracle 租户下还有些缺陷。
Batch INSERT
场景 1/2 能更有效的发挥 Batch 执行的性能,推荐配置如下:
场景 1:
JDBC 对象:
PrepareStatement 对象
Server 端参数:
_ob_enable_prepared_statement=TRUE
JDBC 配置属性:
rewriteBatchedStatements=TRUE
useServerPrepStmts=TRUE
cachePrepStmts=TRUE
prepStmtCacheSize=<根据实际情况>
prepStmtCacheSqlLimit=<根据实际情况>
maxBatchTotalParamsNum=<根据实际情况>
场景 2:
JDBC 对象:
PrepareStatement 对象
JDBC 配置属性:
rewriteBatchedStatements=TRUE
useServerPrepStmts=FALSE
Batch UPDATE
场景 2/3/4 使用了文本协议进行通讯,因此都能利用到多 UPDATE 语句批处理的功能,推荐配置如下:
场景 2:
JDBC 对象:
PrepareStatement 对象
Server 端参数:
ob_enable_batched_multi_statement=TRUE
_enable_static_typing_engine=TRUE(OceanBase V3.2 版本需要)
Server 端变量:
_enable_dist_data_access_service=1(OceanBase V3.2 版本需要)
JDBC 配置属性:
rewriteBatchedStatements=TRUE
useServerPrepStmts=FALSE
allowMultiQueries=TRUE(设置这个是为了避免 JDBC 驱动不同版本间的行为差异)
场景 3/4:
JDBC 对象:
Statement 对象
Server 端参数:
ob_enable_batched_multi_statement=TRUE
_enable_static_typing_engine=TRUE(OceanBase V3.2 版本需要)
Server 端变量:
_enable_dist_data_access_service=1(OceanBase V3.2 版本需要)
JDBC 配置属性:
rewriteBatchedStatements=TRUE
allowMultiQueries=TRUE(设置这个是为了避免 JDBC 驱动不同版本间的行为差异)
如何查看 OceanBase 的 Batch 执行是否生效?
关于查看 OceanBase 的 Batch 执行是否生效,可参考文档 如何查看 OceanBase 的 Batch 执行是否生效。
Batch 执行时,executeBatch 方法返回的值是多少?
executeBatch 方法被调用后,会返回一个整型数组 int []。对于 Batch INSERT 和 Batch UPDATE 来说:
- 如果在 OceanBase 端最终是依次执行的,那么这个数组会返回 Batch 中每一个 Operation 所修改的行数。
- 如果在 OceanBase 端最终是作为一个整体执行的,比如 JDBC 驱动把多条 INSERT 语句改成了一个 INSERT 语句的多个 values(场景1/2);又比如 UPDATE 语句作为一个 batch physical plan 被执行(场景2),那么这个数组的每个元素会返回 -2,表示执行成功但更新行数未知。
适用版本
OceanBase 数据库 V1.x、V2.x、V3.x 版本。