問題描述
在 Oracle 數據庫遷移至 OceanBase 4.2.1 Oracle 租户的過程中,不少研發同學會遇到 SQL 兼容性問題。最近技術部門反饋,一條SQL在Oracle中查詢正常,OceanBase 中查詢報錯ORA-01722: invalid number,表字段是VARCHAR2類型,使用regexp_like過濾數據後,再通過to_number轉換成數字類型。
今天就帶大家深度拆解這個問題的根源,以及對應的解決方案。
報錯的SQL語句如下:
select a.orgunitguid companyid,a.orgname companyname from agentarea a where a.ORGLEVEL = 2 and regexp_like(a.orgunitguid,'^[0-9]+$') and (to_number(a.ORGUNITGUID) BETWEEN 3 and 614 or to_number(a.ORGUNITGUID) BETWEEN 769 and 1624 or to_number(a.ORGUNITGUID) BETWEEN 1748 and 1926 or to_number(a.ORGUNITGUID) BETWEEN 2850 and 3619 or to_number(a.ORGUNITGUID) BETWEEN 3680 and 5615);
環境信息
源庫Oracle版本:Oracle Database 11g Enterprise Edition Release 11.2.0.4.0
目標庫:OBServer版本號 Server version: OceanBase 4.2.1.11 (r111020032025051316-76704a9622f7e60a1a0b3f962ee2b36a731c644a) (Built May 13 2025 16:41:50)
租户模式:Oracle
問題排查
- OceanBase 庫執行報錯如下
查看錶DDL
obclient(OMS_USER@ecs_t01)[OMS_USER]> show create table agentarea\G
*************************** 1. row ***************************
TABLE: AGENTAREA
CREATE TABLE: CREATE TABLE "AGENTAREA" (
"ORGUNITGUID" VARCHAR2(38) NOT NULL ENABLE,
"PARENTGUID" VARCHAR2(38),
"ORGNAME" VARCHAR2(80) NOT NULL ENABLE,
"ORGLEVEL" NUMBER,
"PATH" VARCHAR2(32767),
"ORGAREA" VARCHAR2(32767)
) COMPRESS FOR ARCHIVE REPLICA_NUM = 3 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
1 row in set (0.005 sec)
obclient(OMS_USER@ecs_t01)[ECS]> select a.orgunitguid companyid,a.orgname companyname from agentarea a
-> where a.ORGLEVEL = 2 and regexp_like(a.orgunitguid,'^[0-9]+$')
-> and
-> (to_number(a.ORGUNITGUID) BETWEEN 3 and 614 or
-> to_number(a.ORGUNITGUID) BETWEEN 769 and 1624 );
ORA-01722: invalid number
[10.79.189.78:2882] [2025-10-22 19:36:14.632670] [YB420A4FBD4E-00063AB339BDB385-0-0]
observer 根據trace_id過濾的關鍵日誌:fail to calc function to_number(ret=-5114, ori_str=system)
observer.log.20251022193708351:[2025-10-22 19:36:14.565436] WDIAG [SQL.ENG] eval_trim (ob_expr_trim.cpp:781) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=6][errcode=0] trim_type is ltrim
observer.log.20251022193708351:[2025-10-22 19:36:14.632199] WDIAG [SQL.ENG] calc_tonumber_expr (ob_expr_to_number.cpp:129) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=1][errcode=-5114] fail to calc function to_number(ret=-5114, ori_str=system)
observer.log.20251022193708351:[2025-10-22 19:36:14.632223] WDIAG [SQL] get_comparator_operands (ob_expr_operator.h:1184) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=23][errcode=-5114] left eval failed(ret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632230] WDIAG [SQL.ENG] def_relational_eval_func (ob_expr_cmp_func.cpp:57) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=7][errcode=-5114] failed to eval args(ret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632243] WDIAG [SQL.ENG] calc_and_exprN (ob_expr_and.cpp:81) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=13][errcode=-5114] eval arg 0 failed(ret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632250] WDIAG [SQL.ENG] calc_or_exprN (ob_expr_or.cpp:125) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=7][errcode=-5114] eval arg 0 failed(ret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632263] WDIAG [SQL.ENG] filter_row (ob_operator.cpp:1300) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=12][errcode=-5114] expr evaluate failed(ret=-5114, eval_ctx={batch_idx:0, batch_size:1, max_batch_size:0, frames_:0x7f8c4396eb20}, expr=0x7fbca6d1c260)
observer.log.20251022193708351:[2025-10-22 19:36:14.632281] WDIAG [SQL.ENG] get_next_row (ob_operator.cpp:1097) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=18][errcode=-5114] filter row failed(ret=-5114, type=32, op="PHY_SUBPLAN_SCAN")
observer.log.20251022193708351:[2025-10-22 19:36:14.632291] WDIAG [SQL.EXE] get_next_row (ob_execute_result.cpp:147) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=8][errcode=-5114] get next row from operator failed(ret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632296] WDIAG [SQL] inner_get_next_row (ob_result_set.cpp:411) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=5][errcode=-5114] get next row from exec result failed(ret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632310] WDIAG [SERVER] response_query_result (ob_query_driver.cpp:306) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=13][errcode=-5114] fail to iterate and response(ret=-5114, row_num=8, can_retry=false)
observer.log.20251022193708351:[2025-10-22 19:36:14.632317] INFO [SERVER] response_query_result (ob_query_driver.cpp:316) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=6] The query has already returned partial results to the client and cannot be retried(ret=-5114, ret="OB_INVALID_NUMERIC")
observer.log.20251022193708351:[2025-10-22 19:36:14.632324] WDIAG [SERVER] response_result (ob_sync_plan_driver.cpp:104) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=6][errcode=-5114] response query result fail(ret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632467] INFO [SQL.EXE] end_stmt (ob_sql_trans_control.cpp:1170) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=5] end stmt(ret=0, plain_select=true, stmt_type=1, savepoint=0, tx_desc={this:0x7fc8ae250260, tx_id:{txid:0}, state:1, addr:"10.79.189.78:2882", tenant_id:1002, session_id:3221712900, assoc_session_id:3221712900, xid:NULL, xa_mode:"", xa_start_addr:"0.0.0.0:0", access_mode:0, tx_consistency_type:0, isolation:1, snapshot_version:{val:18446744073709551615, v:3}, snapshot_scn:0, active_scn:0, op_sn:1, alloc_ts:1761132400954310, active_ts:-1, commit_ts:-1, finish_ts:-1, timeout_us:-1, lock_timeout_us:-1, expire_ts:9223372036854775807, coord_id:{id:-1}, parts:[], exec_info_reap_ts:0, commit_version:{val:18446744073709551615, v:3}, commit_times:0, commit_cb:null, cluster_id:-1, cluster_version:0, flags_.SHADOW:false, flags_.INTERRUPTED:false, flags_.BLOCK:false, flags_.REPLICA:false, can_elr:true, cflict_txs:[], abort_cause:0, commit_expire_ts:0, commit_task_.is_registered():false, modified_tables:[], ref:1}, trans_result={incomplete:false, parts:[], touched_ls_list:[], cflict_txs:[]}, rollback=true, need_rollback=true, session={this:0x7fbb72ac01f8, id:3221712900, deser:false, tenant:"ecs_t01", tenant_id:1002, effective_tenant:"ecs_t01", effective_tenant_id:1002, database:"ECS", user:"OMS_USER", consistency_level:3, session_state:2, autocommit:false, tx:0x7fc8ae250260}, exec_ctx.get_errcode()=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632579] WDIAG [SERVER] response_result (ob_sync_plan_driver.cpp:126) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=62][errcode=-5114] close result set fail(cret=-5114)
observer.log.20251022193708351:[2025-10-22 19:36:14.632652] INFO [SERVER] send_error_packet (obmp_packet_sender.cpp:319) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=9] sending error packet(ob_error=-5114, client error=1722, extra_err_info=NULL, lbt()="0x139d7265 0xace6c60 0xac931c2 0x55bf817 0x557db30 0x55763a6 0x55692da 0x5553d42 0xa99bf74 0x13c9570f 0x7fcf7b94ef1b 0x7fcf7b8861c0")
observer.log.20251022193708351:[2025-10-22 19:36:14.632719] INFO [SERVER] send_error_packet (obmp_packet_sender.cpp:502) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=12] dump txn free route audit_record(value=1048581, session->get_sessid()=3221712900, session->get_proxy_sessid()=743020606433511071)
observer.log.20251022193708351:[2025-10-22 19:36:14.632731] WDIAG [SERVER] do_process (obmp_query.cpp:808) [958194][T1002_L0_G0][T1002][YB420A4FBD4E-00063AB339BDB385-0-0] [lt=9][errcode=-5114] execute query fail(ret=-5114, timeout_timestamp=1761136574492994)
- 將where 條件中的
to_number數字轉換函數條件去掉SQL執行正常
根據報錯日誌的值查詢表中的記錄ori_str=system
obclient(OMS_USER@ecs_t01)[ECS]> select a.orgunitguid companyid,a.orgname companyname from agentarea a where a.ORGUNITGUID='system';
+-----------+-----------------------------------------------------+
| COMPANYID | COMPANYNAME |
+-----------+-----------------------------------------------------+
| system | 測試 |
+-----------+-----------------------------------------------------+
1 row in set (0.187 sec)
-- to_number數字轉換函數條件去掉SQL執行正常
select a.orgunitguid companyid,a.orgname companyname from agentarea a where a.ORGLEVEL = 2 and regexp_like(a.orgunitguid,'^[0-9]+$') ;
192 rows in set (0.537 sec)
explain extended查看SQL的OceanBase 執行計劃
obclient(OMS_USER@ecs_t01)[OMS_USER]> explain extended select a.orgunitguid companyid,a.orgname companyname from agentarea a where a.ORGLEVEL = 2 and regexp_like(a.orgunitguid,'^[0-9]+$') and (to_number(a.ORGUNITGUID) BETWEEN 3 and 614 or to_number(a.ORGUNITGUID) BETWEEN 769 and 1624 or to_number(a.ORGUNITGUID) BETWEEN 1748 and 1926 or to_number(a.ORGUNITGUID) BETWEEN 2850 and 3619 or to_number(a.ORGUNITGUID) BETWEEN 3680 and 5615);
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Query Plan |
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| =============================================== |
| |ID|OPERATOR |NAME|EST.ROWS|EST.TIME(us)| |
| ----------------------------------------------- |
| |0 |TABLE FULL SCAN|A |390 |453 | |
| =============================================== |
| Outputs & filters: |
| ------------------------------------- |
| 0 - output([A.ORGUNITGUID(0x7ed1ec026bd0)], [A.ORGNAME(0x7ed1ec048330)]), filter([A.ORGLEVEL(0x7ed1ec025570) = 2(0x7ed1ec024e20)], [(T_OP_OR, TO_NUMBER(cast(A.ORGUNITGUID(0x7ed1ec026bd0), |
| VARCHAR2(1048576 ))(0x7ed1ec03b810))(0x7ed1ec0297d0) >= 3(0x7ed1ec02ba10) AND TO_NUMBER(cast(A.ORGUNITGUID(0x7ed1ec026bd0), VARCHAR2(1048576 ))(0x7ed1ec03b810))(0x7ed1ec0297d0) |
| = 769(0x7ed1ec02f190) |
| AND TO_NUMBER(cast(A.ORGUNITGUID(0x7ed1ec026bd0), VARCHAR2(1048576 ))(0x7ed1ec03b810))(0x7ed1ec0297d0) = 1748(0x7ed1ec0328b0) AND TO_NUMBER(cast(A.ORGUNITGUID(0x7ed1ec026bd0), VARCHAR2(1048576 ))(0x7ed1ec03b810))(0x7ed1ec0297d0) |
| = 2850(0x7ed1ec036090) |
| AND TO_NUMBER(cast(A.ORGUNITGUID(0x7ed1ec026bd0), VARCHAR2(1048576 ))(0x7ed1ec03b810))(0x7ed1ec0297d0) = 3680(0x7ed1ec0397b0) AND TO_NUMBER(cast(A.ORGUNITGUID(0x7ed1ec026bd0), VARCHAR2(1048576 ))(0x7ed1ec03b810))(0x7ed1ec0297d0) |
| =3 AND
TO_NUMBER("A"."ORGUNITGUID")=769
AND TO_NUMBER("A"."ORGUNITGUID")
查看Oracle 的執行計劃,Oracle是根據謂詞條件REGEXP_LIKE ("A"."ORGUNITGUID",'^[0-9]+$')先過濾,OceanBase 執行的順序是to_number過濾在前。導致查詢到的字符無法轉換為數字類型。
規避方案
針對這個問題,最直接有效的方式是通過改寫SQL的方式,主要內部改寫可能會還原這個SQL,所以增加一個no_rewrite的hint,具體方案如下:
select /*+no_rewrite*/ b.orgunitguid companyid,b.orgname companyname from (select a.orgunitguid,a.orgname from agentarea a where a.ORGLEVEL = 2 and regexp_like(a.orgunitguid,'^[0-9]+$')) b where (to_number(b.ORGUNITGUID) BETWEEN 3 and 614 or to_number(b.ORGUNITGUID) BETWEEN 769 and 1624 or to_number(b.ORGUNITGUID) BETWEEN 1748 and 1926 or to_number(b.ORGUNITGUID) BETWEEN 2850 and 3619 or to_number(b.ORGUNITGUID) BETWEEN 3680 and 5615);
如果你的團隊在 Oracle 遷移 OceanBase 過程中遇到類似兼容性問題,歡迎在評論區留言交流,下次見!
更多技術分享可掃碼關注查看