大数跨境

OceanBase SPM SQL基线跨租户迁移操作手册

OceanBase SPM SQL基线跨租户迁移操作手册 瑞蓝创软件
2026-10-19
5
导读:SQL 执行计划飘忽不定,Plan Cache 一淘汰就性能雪崩?
图片

作者简介:李亚宗,瑞蓝创数据库工程师















原创内容未经授权不得随意使用,转载请联系小编并注明来源


操作背景

生产环境OceanBase(Oracle兼容模式)存在执行计划不稳定问题,Plan Cache容易被淘汰、新生成的执行计划存在性能退化风险。为保障SQL执行计划稳定,需要将调优验证通过的SQL Plan Baseline(SPM基线) 从源租户导出,迁移至目标租户进行固化。

OceanBase兼容Oracle DBMS_SPM 包,支持通过中转临时表方式完成基线跨租户/跨集群迁移,整体流程:创建基线中转表 → 源租户打包基线至临时表 → 导出临时表数据 → 目标租户导入临时表 → 从临时表解包生成基线。

一、源租户基线导出流程

1. 查询当前租户已存在的SQL基线

obclient(SYS@ora)[SYS]> SELECT * FROM DBA_SQL_PLAN_BASELINES;
+----------------------+----------------------------------+----------------------------------------------------------------------------+----------------------+---------+-------------+---------------------+-------------+---------+------------------------------+------------------------------+------------------+------------------+---------+----------+-------+------------+-----------+----------+----------------+--------+--------+------------+--------------+----------+-------------+------------+---------------+----------------+---------+--------------------+
| SIGNATURE            | SQL_HANDLE                       | SQL_TEXT                                                                   | PLAN_NAME            | CREATOR | ORIGIN      | PARSING_SCHEMA_NAME | DESCRIPTION | VERSION | CREATED                      | LAST_MODIFIED                | LAST_EXECUTED    | LAST_VERIFIED    | ENABLED | ACCEPTED | FIXED | REPRODUCED | AUTOPURGE | ADAPTIVE | OPTIMIZER_COST | MODULE | ACTION | EXECUTIONS | ELAPSED_TIME | CPU_TIME | BUFFER_GETS | DISK_READS | DIRECT_WRITES | ROWS_PROCESSED | FETCHES | END_OF_FETCH_COUNT |
+----------------------+----------------------------------+----------------------------------------------------------------------------+----------------------+---------+-------------+---------------------+-------------+---------+------------------------------+------------------------------+------------------+------------------+---------+----------+-------+------------+-----------+----------+----------------+--------+--------+------------+--------------+----------+-------------+------------+---------------+----------------+---------+--------------------+
| 12622318878512683009 | 7B0C04E5D41B3A5688325885C5981C74 | SELECT * FROM sales WHERE quantity>?                                       | 12622318878512683009 | SYS     | MANUAL-LOAD | NULL                | NULL        | 4.3.5.3 | 10-JUL-2604.28.13.011530 PM | 10-JUL-2604.28.13.011530 PM | 1783672092873574 | 1783672092873574 | YES     | YES      | NO    | YES        | YES       | NO       |             -1 | NULL   | NULL   |          2 |        11678 |    11439 |        NULL |       NULL |          NULL |           NULL |    NULL |               NULL |
|  9957455692016257262 | D868ABCC6751FF5A51DD4CCA8849A2B7 | SELECT p.name,s.quantity FROM products p JOIN sales s ON p.id=s.product_id | 9957455692016257262  | SYS     | MANUAL-LOAD | NULL                | NULL        | 4.3.5.3 | 10-JUL-2604.29.43.077632 PM | 10-JUL-2604.29.43.077632 PM | 1783672121079192 | 1783672121079192 | YES     | YES      | NO    | YES        | YES       | NO       |             -1 | NULL   | NULL   |          1 |        15498 |     8097 |        NULL |       NULL |          NULL |           NULL |    NULL |               NULL |
|   392011635145358154 | FF5B0A6A018C4776B09F076275FDD727 | SELECT * FROM products                                                     | 392011635145358154   | SYS     | MANUAL-LOAD | NULL                | NULL        | 4.3.5.3 | 10-JUL-2604.23.14.184482 PM | 10-JUL-2604.23.14.184482 PM | 1783671594499549 | 1783671594499549 | YES     | YES      | NO    | YES        | YES       | NO       |             -1 | NULL   | NULL   |          3 |         3807 |     3569 |        NULL |       NULL |          NULL |           NULL |    NULL |               NULL |
+----------------------+----------------------------------+----------------------------------------------------------------------------+----------------------+---------+-------------+---------------------+-------------+---------+------------------------------+------------------------------+------------------+------------------+---------+----------+-------+------------+-----------+----------+----------------+--------+--------+------------+--------------+----------+-------------+------------+---------------+----------------+---------+--------------------+
3rowsinset (0.007 sec)

2. 创建基线中转临时表

使用系统存储过程生成标准化中转表 TMP_BASELINE

obclient(SYS@ora)[SYS]> call DBMS_SPM.CREATE_STGTAB_BASELINE('TMP_BASELINE');
Query OK, 0 rows affected (3.203 sec)

3. 将基线打包写入中转表

方式1:导出指定单条基线(通过plan_hash_value)

obclient(SYS@ora)[SYS]> BEGIN 
DBMS_SPM.PACK_STGTAB_BASELINE(table_name=>'TMP_BASELINE',plan_hash=>392011635145358154);  
END;
/
Query OK, 1 row affected (0.195 sec)

obclient(SYS@ora)[SYS]> COMMIT;
Query OK, 0 rows affected (0.010 sec)

验证打包结果:

obclient(SYS@ora)[SYS]> SELECT * FROM TMP_BASELINE;
+-------------+----------------------------------+--------------------+----------+-----------+-------------+--------+------------+-----------------------------------------------------------------------------------------------------------------------+-------+------------------+------------------+----------------+------------+--------------+----------+------------------------+------------------------+--------+--------+--------+--------+--------+--------+
| BASELINE_ID | SQL_ID                           | PLAN_HASH_VALUE    | SYS_VARS | PLAN_TYPE | DESCRIPTION | ORIGIN | DB_VERSION | OUTLINE_DATA                                                                                                          | FLAGS | LAST_VERIFIED    | LAST_EXECUTED    | OPTIMIZER_COST | EXECUTIONS | ELAPSED_TIME | CPU_TIME | ORIGIN_SQL             | CONSTRUCTED_SQL        | SPARE1 | SPARE2 | SPARE3 | SPARE4 | SPARE5 | SPARE6 |
+-------------+----------------------------------+--------------------+----------+-----------+-------------+--------+------------+-----------------------------------------------------------------------------------------------------------------------+-------+------------------+------------------+----------------+------------+--------------+----------+------------------------+------------------------+--------+--------+--------+--------+--------+--------+
|           1 | FF5B0A6A018C4776B09F076275FDD727 | 392011635145358154 | NULL     |         1 | NULL        |      2 | 4.3.5.3    | /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "SYS"."PRODUCTS"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.3.5.3') END_OUTLINE_DATA*/ |    27 | 1783671594499549 | 1783671594499549 |             -1 |          3 |         3807 |     3569 | SELECT * FROM products | SELECT * FROM products |   NULL |   NULL |   NULL | NULL   | NULL   | NULL   |
+-------------+----------------------------------+--------------------+----------+-----------+-------------+--------+------------+-----------------------------------------------------------------------------------------------------------------------+-------+------------------+------------------+----------------+------------+--------------+----------+------------------------+------------------------+--------+--------+--------+--------+--------+--------+
1 row in set (0.023 sec)

方式2:导出租户内全部基线(不指定plan_hash)

obclient(SYS@ora)[SYS]> BEGIN 
DBMS_SPM.PACK_STGTAB_BASELINE(table_name=>'TMP_BASELINE');  
END;
/
Query OK, 1 row affected (0.219 sec)

obclient(SYS@ora)[SYS]> COMMIT;
Query OK, 0 rows affected (0.006 sec)

查看全部基线打包数据:

obclient(SYS@ora)[SYS]> SELECT * FROM TMP_BASELINE;
+-------------+----------------------------------+----------------------+----------+-----------+-------------+--------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+------------------+------------------+----------------+------------+--------------+----------+----------------------------------------------------------------------------+----------------------------------------------------------------------------+--------+--------+--------+--------+--------+--------+
| BASELINE_ID | SQL_ID                           | PLAN_HASH_VALUE      | SYS_VARS | PLAN_TYPE | DESCRIPTION | ORIGIN | DB_VERSION | OUTLINE_DATA                                                                                                                                                                                                                                                                                                               | FLAGS | LAST_VERIFIED    | LAST_EXECUTED    | OPTIMIZER_COST | EXECUTIONS | ELAPSED_TIME | CPU_TIME | ORIGIN_SQL                                                                 | CONSTRUCTED_SQL                                                            | SPARE1 | SPARE2 | SPARE3 | SPARE4 | SPARE5 | SPARE6 |
+-------------+----------------------------------+----------------------+----------+-----------+-------------+--------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+------------------+------------------+----------------+------------+--------------+----------+----------------------------------------------------------------------------+----------------------------------------------------------------------------+--------+--------+--------+--------+--------+--------+
|           1 | FF5B0A6A018C4776B09F076275FDD727 |   392011635145358154 | NULL     |         1 | NULL        |      2 | 4.3.5.3    | /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "SYS"."PRODUCTS"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.3.5.3') END_OUTLINE_DATA*/                                                                                                                                                                                                      |    27 | 1783671594499549 | 1783671594499549 |             -1 |          3 |         3807 |     3569 | SELECT * FROM products                                                     | SELECT * FROM products                                                     |   NULL |   NULL |   NULL | NULL   | NULL   | NULL   |
|           2 | 7B0C04E5D41B3A5688325885C5981C74 | 12622318878512683009 | NULL     |         1 | NULL        |      2 | 4.3.5.3    | /*+BEGIN_OUTLINE_DATA FULL(@"SEL$1" "SYS"."SALES"@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.3.5.3') END_OUTLINE_DATA*/                                                                                                                                                                                                         |    27 | 1783672092873574 | 1783672092873574 |             -1 |          2 |        11678 |    11439 | SELECT * FROM sales WHERE quantity>?                                       | SELECT * FROM sales WHERE quantity>?                                       |   NULL |   NULL |   NULL | NULL   | NULL   | NULL   |
|           3 | D868ABCC6751FF5A51DD4CCA8849A2B7 |  9957455692016257262 | NULL     |         3 | NULL        |      2 | 4.3.5.3    | /*+BEGIN_OUTLINE_DATA LEADING(@"SEL$C6D21C0F" ("P"@"SEL$1" "S"@"SEL$1")) USE_HASH(@"SEL$C6D21C0F" "S"@"SEL$1") PQ_DISTRIBUTE(@"SEL$C6D21C0F" "S"@"SEL$1" LOCAL LOCAL) FULL(@"SEL$C6D21C0F" "P"@"SEL$1") FULL(@"SEL$C6D21C0F" "S"@"SEL$1") OUTER_TO_INNER(@"SEL$1") OPTIMIZER_FEATURES_ENABLE('4.3.5.3') END_OUTLINE_DATA*/ |    27 | 1783672121079192 | 1783672121079192 |             -1 |          1 |        15498 |     8097 | SELECT p.name,s.quantity FROM products p JOIN sales s ON p.id=s.product_id | SELECT p.name,s.quantity FROM products p JOIN sales s ON p.id=s.product_id |   NULL |   NULL |   NULL | NULL   | NULL   | NULL   |
+-------------+----------------------------------+----------------------+----------+-----------+-------------+--------+------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-------+------------------+------------------+----------------+------------+--------------+----------+----------------------------------------------------------------------------+----------------------------------------------------------------------------+--------+--------+--------+--------+--------+--------+
3 rows in set (0.007 sec)

4. 使用obdumper导出中转表CSV文件

[root@observer1 bin]# ./obdumper -h 192.168.5.51 -P 2883 -u SYS -t ora -c obcluster435 -p aaAA11__ -D SYS --table TMP_BASELINE -f dumpdata/export_baseline --csv --skip-check-dir
2026-07-10 17:12:00 [INFO] Parsed args:
[--csv] true
[--file-path] dumpdata/export_baseline
[--host] 192.168.5.51
[--port] 2883
[--user] SYS
[--tenant] ora
[--cluster] obcluster435
[--password] ******
[--database] SYS
[--sys-user] root
[--table] [TMP_BASELINE]
[--skip-check-dir] true
[--column-quote-mode] NON_NUMERIC

2026-07-10 17:12:02 [INFO] Trying to establish JDBC connection to `SYS@ora#obcluster435`...
2026-07-10 17:12:02 [INFO] Server Mode: OBORACLE-4.3.5.3
2026-07-10 17:12:02 [INFO] Start executing the task of '"SYS"' database...
2026-07-10 17:12:02 [INFO] Log files will be written to dumpdata/export_baseline/logs
2026-07-10 17:12:02 [INFO] Trying to establish JDBC connection to `SYS@ora#obcluster435`...
2026-07-10 17:12:02 [INFO] Server Mode: OBORACLE-4.3.5.3
2026-07-10 17:12:03 [INFO] Manifest "dumpdata/export_baseline/.MANIFEST.bin" has been saved
2026-07-10 17:12:03 [INFO] Querying table column metadata, this might take a while...
2026-07-10 17:12:04 [INFO] Filtering out empty tables...
2026-07-10 17:12:04 [INFO] Preloading all primary keys...
2026-07-10 17:12:04 [INFO] Version: 4.3.5
2026-07-10 17:12:04 [INFO] Parallel write is set to false.
2026-07-10 17:12:04 [INFO] A total of 1 TABLE need to be dumped.
2026-07-10 17:12:08 [INFO] Query table entry for table "TMP_BASELINE" success. Elapsed: 3.399 s
2026-07-10 17:12:08 [INFO] Generating sub-tasks for table "TMP_BASELINE" by partitions and primary/unique keys...
2026-07-10 17:12:08 [INFO] Generate 1 sub-tasks for table "TMP_BASELINE" succeed. Elapsed: 57.99 ms
2026-07-10 17:12:08 [INFO] TABLE "TMP_BASELINE" is dumping, and several objects are waiting. Remain: [0/1]
2026-07-10 17:12:08 [INFO] Start up the log reporter task succeed.
2026-07-10 17:12:08 [INFO] Start 32 record dump threads for 1 dump tasks finished
2026-07-10 17:12:08 [INFO] Dump data to "dumpdata/export_baseline/data/SYS/TABLE/TMP_BASELINE.csv" finished.
2026-07-10 17:12:08 [INFO] Merge file 'dumpdata/export_baseline/data/SYS/TABLE/TMP_BASELINE.csv' of table 'TMP_BASELINE' finished. Elapsed: 12.65 ms. Remain: [0/1]
2026-07-10 17:12:09 [INFO] ----------   Finished Tasks: 1       Running Tasks: 0        Progress: 100.00%       Finished File Merge Tasks: 1    Running File Merge Tasks: 0----------
2026-07-10 17:12:09 [INFO] 

All Dump Tasks In Database [SYS] Finished: 

----------------------------------------------------------------------------------------------------------------------------
        No.#        |        Type        |             Name             |            Count             |       Status       
----------------------------------------------------------------------------------------------------------------------------
         1          |       TABLE        |         TMP_BASELINE         |              4               |      SUCCESS       
----------------------------------------------------------------------------------------------------------------------------

Total Count: 4          End Time: 2026-07-10 17:12:09

2026-07-10 17:12:09 [INFO] Dump record finished. Total Elapsed: 4.634 s
2026-07-10 17:12:09 [INFO] System exit 0

二、目标租户(test1)基线导入流程

1. 预先检查目标租户基线(初始为空)

obclient(SYS@test1)[SYS]> select * from DBA_SQL_PLAN_BASELINES;
Empty set (0.049 sec)

2. 目标租户创建相同结构中转表

obclient(SYS@test1)[SYS]> call DBMS_SPM.CREATE_STGTAB_BASELINE('TMP_BASELINE');

3. obloader 将CSV数据导入中转表

注意:中转表 BASELINE_ID 为自增列,导入时配置控制文件跳过自增主键冲突

[root@observer1 bin]# ./obloader -h 172.18.8.17 -P 2881 -u SYS -t test1 -p aaAA11__ -D SYS --table TMP_BASELINE -f dumpdata/export_baseline --csv --ctl-path /root/controls/
2026-07-10 19:14:49 [INFO] Parsed args:
[--csv] true
[--ctl-path] /root/controls/
[--file-path] dumpdata/export_baseline
[--host] 172.18.8.17
[--port] 2881
[--user] SYS
[--tenant] test1
[--password] ******
[--database] SYS
[--sys-user] root
[--table] [TMP_BASELINE]

2026-07-10 19:14:51 [INFO] Trying to establish JDBC connection to `SYS@test1`...
2026-07-10 19:14:51 [INFO] Server Mode: OBORACLE-4.2.5.5
2026-07-10 19:14:51 [INFO] Start executing the task of '"SYS"' database...
2026-07-10 19:14:52 [INFO] Log files will be written to dumpdata/export_baseline/logs
2026-07-10 19:14:52 [INFO] Trying to establish JDBC connection to `SYS@test1`...
2026-07-10 19:14:52 [INFO] Server Mode: OBORACLE-4.2.5.5
2026-07-10 19:14:52 [INFO] Parse ctrl definition: "/root/controls/TMP_BASELINE.ctrl" success
2026-07-10 19:14:53 [INFO] Manifest has been saved to "dumpdata/export_baseline/.MANIFEST.bin"
2026-07-10 19:14:53 [INFO] Version: 4.3.5
2026-07-10 19:14:53 [INFO] Querying table column metadata, this might take a while...
2026-07-10 19:14:53 [INFO] Listing all matched data files in dest path...
2026-07-10 19:14:53 [INFO] Binding table: "SYS"."TMP_BASELINE" to file: "file:/root/ob-loader-dumper-4.3.5-RELEASE/bin/dumpdata/export_baseline/data/SYS/TABLE/TMP_BASELINE.csv" finished
2026-07-10 19:14:53 [INFO] Find 1 data files in: "dumpdata/export_baseline" success. Elapsed: 36.41 ms
2026-07-10 19:14:53 [INFO] Splitting data files into 64 MB logical chunks...
2026-07-10 19:14:53 [INFO] Split 1 data files to 1 logical chunks success. Elapsed: 46.03 ms
2026-07-10 19:14:53 [INFO] Querying primary/unique constraints metadata for data replacing...
2026-07-10 19:14:53 [INFO] Partition calculation flag is true
2026-07-10 19:14:53 [INFO] Query entry for table: "TMP_BASELINE" finished. Remain: [0/1]
2026-07-10 19:14:53 [INFO] Query leader location of table: "TMP_BASELINE" finished. Remain: [0/1]
2026-07-10 19:14:53 [INFO] Waiting to calculate leader for 1 sub-files....
2026-07-10 19:14:53 [INFO] Use c.l.d.SleepingWaitStrategy as available cpu(s) is 16
2026-07-10 19:14:53 [INFO] Create 4096 slots for ring buffer and leader server [172.18.8.17:2881] succeed.
2026-07-10 19:14:53 [INFO] Start 32 writers for 32 threads and leader server [172.18.8.17:2881] succeed.
2026-07-10 19:14:53 [INFO] Start 1 readers for 32 threads succeed.
2026-07-10 19:14:54 [INFO] Reset batch size [0->200] for table "TMP_BASELINE".
2026-07-10 19:14:54 [INFO] 
---------------------------------------------------------------------------------------------------------
OBServerLoadThrottle: 
        Server:       172.18.8.17:2881   Merge Status: false     Mem Used Ratio:   9%    Load Mode:  FAST
---------------------------------------------------------------------------------------------------------
DummyGCThrottle: 
        Name:    G1 Young Generation     GC Count:     2         GC Cost:    00:00:00.106
        Name:      G1 Old Generation     GC Count:     0         GC Cost:    00:00:00.000
---------------------------------------------------------------------------------------------------------
RingBufferThrottle: Blocking: false
---------------------------------------------------------------------------------------------------------
MemoryThrottle: [HEAP_MEM: 51.6 MB/4 GB], [NON_HEAP_MEM: 53.8 MB/488 MB], Block Possible: 0 %
---------------------------------------------------------------------------------------------------------
TpsThrottle: [Tps: 2147483647], Blocking: false
---------------------------------------------------------------------------------------------------------

2026-07-10 19:14:54 [INFO] File: "/root/ob-loader-dumper-4.3.5-RELEASE/bin/dumpdata/export_baseline/data/SYS/TABLE/TMP_BASELINE.csv" has been read finished.
2026-07-10 19:14:54 [INFO] Block Threads: 0
---------------------------------------------------------------------------------------------------------
ThreadSubmitTpsThrottle: [Tps: 1.0000], Blocking: false
---------------------------------------------------------------------------------------------------------
ThreadSubmitMemThrottle: [HEAP_MEM: 51.6 MB/4 GB], [NON_HEAP_MEM: 54.0 MB/488 MB], Block Possible: 0 %
---------------------------------------------------------------------------------------------------------

2026-07-10 19:14:55 [INFO] ----------   Finished Tasks: 1       Running Tasks: 0        Progress: 100.00%       ----------
2026-07-10 19:14:55 [INFO] 

All Load Tasks In Database [SYS] Finished: 

----------------------------------------------------------------------------------------------------------------------------
        No.#        |        Type        |             Name             |            Count             |       Status       
----------------------------------------------------------------------------------------------------------------------------
         1          |       TABLE        |         TMP_BASELINE         |            4 -> 4            |      SUCCESS       
----------------------------------------------------------------------------------------------------------------------------

Total Count: 4          End Time: 2026-07-10 19:14:55

2026-07-10 19:14:55 [INFO] Load record finished. Total Elapsed: 2.032 s
2026-07-10 19:14:55 [INFO] System exit 0

4. 从临时表解包,生成正式SQL基线

obclient(SYS@test1)[SYS]> call DBMS_SPM.UNPACK_STGTAB_BASELINE('TMP_BASELINE');
Query OK, 0 rows affected (0.021 sec)

5. 结果验证

执行 SELECT * FROM DBA_SQL_PLAN_BASELINES;,可以查看到基线已经成功导入目标租户,基线生效。

三、重要注意事项(补充)

  1. 版本兼容风险:本次迁移源4.3.5.3 → 目标4.2.5.5,跨小版本。OUTLINE中包含OPTIMIZER_FEATURES_ENABLE版本标记,低版本数据库可能无法识别部分hint,导入后务必压测验证SQL性能。
  2. Schema适配:基线内表名默认为原租户Schema,如果源、目标租户表不在同一Schema,基线可能失效,需要改写SQL或者调整表访问方式。
  3. 基线状态检查:导入后重点确认:ENABLED=YES、ACCEPTED=YES,只有同时满足两个条件,优化器才会优先选用该基线计划。
  4. 迁移完成清理:验证基线正常生效后,建议删除两端 TMP_BASELINE 中转临时表,避免残留元数据。
  5. 替代方案对比:除SPM基线迁移外,也可通过CREATE OUTLINE 固化计划;但SPM基线支持批量迁移,适合大批量SQL治理场景。

如果在操作过程中遇到问题,欢迎在评论区留言交流,后续我们会持续分享更多实战运维干货,记得关注不迷路,下次见~

END


瑞蓝创 OceanBase OBCP V4 精英训练营

点击下方图片立即了解详情

瑞蓝创02.png


··
·

·

▼ 点击「阅读原文」,了解更多产品技术文章

【声明】内容源于网络
0
0
瑞蓝创软件
专注于企业信息科技战略咨询、数据中心规划及运维、智能化软件产品研发,致力于为金融、能源、电信、制造等行业提供智能的业务永续及流程自动化解决方案。
内容 85
粉丝 0
瑞蓝创软件 专注于企业信息科技战略咨询、数据中心规划及运维、智能化软件产品研发,致力于为金融、能源、电信、制造等行业提供智能的业务永续及流程自动化解决方案。
总阅读1.6k
粉丝0
内容85