实践练习六(必选):OceanBase TPC-C 测试和查看 执行计划

实践练习六(必选):OceanBase TPC-C 测试和查看 执行计划

练习目的

本次练习目的掌握 OceanBase 的执行计划查看方法,包括 explain 命令和查看实际执行计划。

练习条件

  • 有 服务器,内存资源至少 12G*1 台,部署有 OceanBase 集群(单副本或三副本都可以)。

练习内容

请记录并分享下列内容:

  • (必选)使用 BenmarkSQL 运行 TPC-C ,并发数不用很高,5~10 并发即可(根据机器资源)。
  • (必选)分析 TPC-C TOP SQL,并查看 3条 SQL 的 解析执行计划 和 实际执行计划。
  • (可选)使用 OceanBase 的 Outline 对 其中一条 SQL 进行限流(限制并发为 1 )。
  • (可选)导入 TPC-H schema 和数据,数据量不用太大 100M 即可。查看 TPC-H 5条 SQL 的解析执行计划和实际执行计划。

1. 使用 BenmarkSQL 运行 TPC-C

1.1 BenchmarkSQL 下载

# 下载 BenmarkSQL 
https://github.com/obpilot/benchmarksql-5.0-master/archive/refs/heads/master.zip

1.2 BenchmarkSQL 准备

[aicenter@aicenter2 package]$ mkdir /data/aicenter/software/BenchmarkSQL 
[aicenter@aicenter2 package]$ unzip benchmarksql-5.0-master-master.zip -d /data/aicenter/software/BenchmarkSQL/
[aicenter@aicenter2 package]$ cd /data/aicenter/software/BenchmarkSQL 
[aicenter@aicenter2 BenchmarkSQL]$ ll
总用量 4
drwxrwxr-x. 8 aicenter aicenter 4096 229 2020 benchmarksql-5.0-master-master
[aicenter@aicenter2 BenchmarkSQL]$ ll benchmarksql-5.0-master-master/
总用量 44
drwxrwxr-x. 2 aicenter aicenter 4096 229 2020 build
-rwxr-xr-x. 1 aicenter aicenter 1130 229 2020 build.xml
drwxrwxr-x. 2 aicenter aicenter 4096 229 2020 dist
drwxrwxr-x. 3 aicenter aicenter 4096 229 2020 doc
-rwxr-xr-x. 1 aicenter aicenter 6376 229 2020 HOW-TO-RUN.txt
drwxrwxr-x. 5 aicenter aicenter 4096 229 2020 lib
-rwxr-xr-x. 1 aicenter aicenter 5470 229 2020 README.md
drwxrwxr-x. 8 aicenter aicenter 4096 229 2020 run
drwxrwxr-x. 6 aicenter aicenter 4096 229 2020 src

# 验证 Java 环境 (需要有 JAVA 运行环境,版本不低于 V1.8.0)
[aicenter@aicenter2 BenchmarkSQL]$ source /etc/profile
[aicenter@aicenter2 BenchmarkSQL]$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

1.3 创建测试库及用户

[aicenter@aicenter2 BenchmarkSQL]$ mysql -h 172.17.0.2 -uroot@obmysql -P2883 -p 
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 36
Server version: 5.6.25 OceanBase 3.1.1 (r4-8c615943cbd25a6f7b8bdfd8677a13a21709a05e) (Built Oct 21 2021 10:52:05)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> create database tpcc;
Query OK, 1 row affected (0.03 sec)

mysql> CREATE USER 'tpcc'@'%' IDENTIFIED BY '123456';
Query OK, 0 rows affected (0.03 sec)

mysql> GRANT ALL ON tpcc.* TO 'tpcc'@'%';
Query OK, 0 rows affected (0.04 sec)

mysql> exit
Bye

1.4 配置文件 props.ob

benchmarksql-5.0-master/run 目录下。

[aicenter@aicenter2 BenchmarkSQL]$ vim benchmarksql-5.0-master/run/props.ob 

db=oracle
driver=com.alipay.oceanbase.obproxy.mysql.jdbc.Driver
conn=jdbc:oceanbase://172.17.0.2:2883/tpcc?useUnicode=true&characterEncoding=utf-8
user=tpcc@obmysql#obce-single
password=123456

warehouses=2
loadWorkers=10

terminals=10
//To run specified transactions per terminal- runMins must equal zero
runTxnsPerTerminal=0
//To run for specified minutes- runTxnsPerTerminal must equal zero
runMins=10
//Number of total transactions per minute
limitTxnsPerMin=0

//Set to true to run in 4.x compatible mode. Set to false to use the
//entire configured database evenly.
terminalWarehouseFixed=true

//The following five values must add up to 100
newOrderWeight=45
paymentWeight=43
orderStatusWeight=4
deliveryWeight=4
stockLevelWeight=4

// Directory name to create for collecting detailed result data.
// Comment this out to suppress.
resultDirectory=my_result_%tY-%tm-%td_%tH%tM%tS
osCollectorScript=./misc/os_collector_linux.py
osCollectorInterval=1

1.5 下载 OceanBase 驱动文件

# 下载 驱动文件 oceanbase-client-x.x.x.jar
wget https://oceanbase-aliyun-docs.oss-cn-hangzhou.aliyuncs.com/downloads/obclient/oceanbase-client-1.1.10.jar?spm=a2c4g.11186623.0.0.27aa32a9CrISr4&file=oceanbase-client-1.1.10.jar

# 把 OceanBase 数据库的驱动放到 lib/ 目录或 lib/oracle 下即可
[aicenter@aicenter2 package]$ mv oceanbase-client-1.1.10.jar /data/aicenter/software/BenchmarkSQL/benchmarksql-5.0-master/lib/
[aicenter@aicenter2 package]$ ll /data/aicenter/software/BenchmarkSQL/benchmarksql-5.0-master/lib/
总用量 4300
-rw-r--r--. 1 aicenter aicenter  346729 217 16:48 apache-log4j-extras-1.1.jar
drwxr-xr-x. 2 aicenter aicenter    4096 217 16:48 firebird
-rw-r--r--. 1 aicenter aicenter  489883 217 16:48 log4j-1.2.17.jar
-rw-rw-r--. 1 aicenter aicenter 3549756 217 17:31 oceanbase-client-1.1.10.jar
drwxr-xr-x. 2 aicenter aicenter    4096 217 16:48 oracle
drwxr-xr-x. 2 aicenter aicenter    4096 217 16:48 postgres

1.6 准备数据

[aicenter@aicenter2 sql.common]$ cp tableCreates.sql mysql-tableCreates.sql 
[aicenter@aicenter2 sql.common]$ sed -i 's/varchar2/varchar/g' mysql-tableCreates.sql 


# 建表 (有非分区表和分区表之别)
[aicenter@aicenter2 run]$ ./runSQL.sh props.ob sql.common/mysql-tableCreates.sql 
# ------------------------------------------------------------
# Loading SQL file sql.common/mysql-tableCreates.sql
# ------------------------------------------------------------
create table bmsql_config (
cfg_name    varchar(30) primary key,
cfg_value   varchar(50)
);
create table bmsql_warehouse (
w_id        integer   not null,
w_ytd       decimal(12,2),
w_tax       decimal(4,4),
w_name      varchar(10),
w_street_1  varchar(20),
w_street_2  varchar(20),
w_city      varchar(20),
w_state     char(2),
w_zip       char(9)
);
create table bmsql_district (
d_w_id       integer       not null,
d_id         integer       not null,
d_ytd        decimal(12,2),
d_tax        decimal(4,4),
d_next_o_id  integer,
d_name       varchar(10),
d_street_1   varchar(20),
d_street_2   varchar(20),
d_city       varchar(20),
d_state      char(2),
d_zip        char(9)
);
create table bmsql_customer (
c_w_id         integer        not null,
c_d_id         integer        not null,
c_id           integer        not null,
c_discount     decimal(4,4),
c_credit       char(2),
c_last         varchar(16),
c_first        varchar(16),
c_credit_lim   decimal(12,2),
c_balance      decimal(12,2),
c_ytd_payment  decimal(12,2),
c_payment_cnt  integer,
c_delivery_cnt integer,
c_street_1     varchar(20),
c_street_2     varchar(20),
c_city         varchar(20),
c_state        char(2),
c_zip          char(9),
c_phone        char(16),
c_since        timestamp,
c_middle       char(2),
c_data         varchar(500)
);
create sequence bmsql_hist_id_seq;
You have an error in your SQL syntax; check the manual that corresponds to your OceanBase version for the right syntax to use near 'sequence bmsql_hist_id_seq' at line 1
create table bmsql_history (
hist_id  integer,
h_c_id   integer,
h_c_d_id integer,
h_c_w_id integer,
h_d_id   integer,
h_w_id   integer,
h_date   timestamp,
h_amount decimal(6,2),
h_data   varchar(24)
);
create table bmsql_new_order (
no_w_id  integer   not null,
no_d_id  integer   not null,
no_o_id  integer   not null
);
create table bmsql_oorder (
o_w_id       integer      not null,
o_d_id       integer      not null,
o_id         integer      not null,
o_c_id       integer,
o_carrier_id integer,
o_ol_cnt     integer,
o_all_local  integer,
o_entry_d    timestamp
);
create table bmsql_order_line (
ol_w_id         integer   not null,
ol_d_id         integer   not null,
ol_o_id         integer   not null,
ol_number       integer   not null,
ol_i_id         integer   not null,
ol_delivery_d   timestamp,
ol_amount       decimal(6,2),
ol_supply_w_id  integer,
ol_quantity     integer,
ol_dist_info    char(24)
);
create table bmsql_item (
i_id     integer      not null,
i_name   varchar(24),
i_price  decimal(5,2),
i_data   varchar(50),
i_im_id  integer
);
create table bmsql_stock (
s_w_id       integer       not null,
s_i_id       integer       not null,
s_quantity   integer,
s_ytd        integer,
s_order_cnt  integer,
s_remote_cnt integer,
s_data       varchar(50),
s_dist_01    char(24),
s_dist_02    char(24),
s_dist_03    char(24),
s_dist_04    char(24),
s_dist_05    char(24),
s_dist_06    char(24),
s_dist_07    char(24),
s_dist_08    char(24),
s_dist_09    char(24),
s_dist_10    char(24)
);

# 加载数据 (加载数据就是做数据初始化,仓库数越多加载时间越长。具体性能取决于机器配置。)
[aicenter@aicenter2 run]$ ./runLoader.sh props.ob
Starting BenchmarkSQL LoadData

driver=com.alipay.oceanbase.obproxy.mysql.jdbc.Driver
conn=jdbc:oceanbase://172.17.0.2:2883/tpcc?useUnicode=true&characterEncoding=utf-8
user=tpcc@obmysql#obce-single
password=***********
warehouses=2
loadWorkers=10
fileLocation (not defined)
csvNullValue (not defined - using default 'NULL')

Worker 000: Loading ITEM
Worker 001: Loading Warehouse      1
Worker 002: Loading Warehouse      2
Worker 000: Loading ITEM done
Worker 002: ERROR: Transaction is timeout
Worker 001: ERROR: Transaction is timeout
# 事务超时处理 ,调整事务超时参数
[aicenter@aicenter2 run]$ mysql -h 172.17.0.2 -uroot@obmysql -P2883 -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 43
Server version: 5.6.25 OceanBase 3.1.1 (r4-8c615943cbd25a6f7b8bdfd8677a13a21709a05e) (Built Oct 21 2021 10:52:05)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> show variables like '%timeout%';
+---------------------+------------------+
| Variable_name       | Value            |
+---------------------+------------------+
| connect_timeout     | 10               |
| interactive_timeout | 28800            |
| lock_wait_timeout   | 31536000         |
| net_read_timeout    | 30               |
| net_write_timeout   | 60               |
| ob_pl_block_timeout | 3216672000000000 |
| ob_query_timeout    | 10000000         |
| ob_trx_idle_timeout | 120000000        |
| ob_trx_lock_timeout | -1               |
| ob_trx_timeout      | 100000000        |
| wait_timeout        | 28800            |
+---------------------+------------------+
11 rows in set (0.00 sec)

mysql> set global ob_trx_timeout=10000000000;
Query OK, 0 rows affected (0.92 sec)

mysql> set global ob_query_timeout=100000000;
Query OK, 0 rows affected (0.03 sec)

mysql> exit
Bye

[aicenter@aicenter2 run]$ ./runLoader.sh props.ob
Starting BenchmarkSQL LoadData

driver=com.alipay.oceanbase.obproxy.mysql.jdbc.Driver
conn=jdbc:oceanbase://172.17.0.2:2883/tpcc?useUnicode=true&characterEncoding=utf-8
user=tpcc@obmysql#obce-single
password=***********
warehouses=2
loadWorkers=10
fileLocation (not defined)
csvNullValue (not defined - using default 'NULL')

Worker 000: Loading ITEM
Worker 001: Loading Warehouse      1
Worker 002: Loading Warehouse      2
Worker 000: Loading ITEM done
Worker 002: Loading Warehouse      2 done
Worker 001: Loading Warehouse      1 done

# 创建索引 (当数据初始化完后再补充两个索引)
[aicenter@aicenter2 run]$ ./runSQL.sh props.ob sql.oceanbase/indexCreates.sql
# ------------------------------------------------------------
# Loading SQL file sql.oceanbase/indexCreates.sql
# ------------------------------------------------------------
create index bmsql_customer_idx1
on  bmsql_customer (c_w_id, c_d_id, c_last, c_first) local;
create  index bmsql_oorder_idx1
on  bmsql_oorder (o_w_id, o_d_id, o_carrier_id, o_id) local;

1.7 性能测试

数据初始化确认没有错误(没有仓库数据报错),就可以跑性能测试。TPC-C 用 tpmC 值(Transactions per Minute)来衡量系统最大有效吞吐量。 其中 Transactions 以 NewOrder Transaction 为准,即最终衡量单位为每分钟处理的订单数。

# 性能测试
[aicenter@aicenter2 run]$ ./runBenchmark.sh props.ob
19:10:13,524 [main] INFO   jTPCC : Term-00, 
19:10:13,528 [main] INFO   jTPCC : Term-00, +-------------------------------------------------------------+
19:10:13,528 [main] INFO   jTPCC : Term-00,      BenchmarkSQL v5.0
19:10:13,528 [main] INFO   jTPCC : Term-00, +-------------------------------------------------------------+
19:10:13,528 [main] INFO   jTPCC : Term-00,  (c) 2003, Raul Barbosa
19:10:13,528 [main] INFO   jTPCC : Term-00,  (c) 2004-2016, Denis Lussier
19:10:13,531 [main] INFO   jTPCC : Term-00,  (c) 2016, Jan Wieck
19:10:13,531 [main] INFO   jTPCC : Term-00, +-------------------------------------------------------------+
19:10:13,531 [main] INFO   jTPCC : Term-00, 
19:10:13,531 [main] INFO   jTPCC : Term-00, db=oracle
19:10:13,532 [main] INFO   jTPCC : Term-00, driver=com.alipay.oceanbase.obproxy.mysql.jdbc.Driver
19:10:13,532 [main] INFO   jTPCC : Term-00, conn=jdbc:oceanbase://172.17.0.2:2883/tpcc?useUnicode=true&characterEncoding=utf-8
19:10:13,532 [main] INFO   jTPCC : Term-00, user=tpcc@obmysql#obce-single
19:10:13,532 [main] INFO   jTPCC : Term-00, 
19:10:13,532 [main] INFO   jTPCC : Term-00, warehouses=2
19:10:13,532 [main] INFO   jTPCC : Term-00, terminals=10
19:10:13,534 [main] INFO   jTPCC : Term-00, runMins=10
19:10:13,535 [main] INFO   jTPCC : Term-00, limitTxnsPerMin=0
19:10:13,535 [main] INFO   jTPCC : Term-00, terminalWarehouseFixed=true
19:10:13,535 [main] INFO   jTPCC : Term-00, 
19:10:13,535 [main] INFO   jTPCC : Term-00, newOrderWeight=45
19:10:13,535 [main] INFO   jTPCC : Term-00, paymentWeight=43
19:10:13,535 [main] INFO   jTPCC : Term-00, orderStatusWeight=4
19:10:13,535 [main] INFO   jTPCC : Term-00, deliveryWeight=4
19:10:13,535 [main] INFO   jTPCC : Term-00, stockLevelWeight=4
19:10:13,535 [main] INFO   jTPCC : Term-00, 
19:10:13,536 [main] INFO   jTPCC : Term-00, resultDirectory=my_result_%tY-%tm-%td_%tH%tM%tS
19:10:13,536 [main] INFO   jTPCC : Term-00, osCollectorScript=./misc/os_collector_linux.py
19:10:13,536 [main] INFO   jTPCC : Term-00, 
19:10:13,580 [main] INFO   jTPCC : Term-00, copied props.ob to my_result_2022-02-17_191013/run.properties
19:10:13,581 [main] INFO   jTPCC : Term-00, created my_result_2022-02-17_191013/data/runInfo.csv for runID 6
19:10:13,581 [main] INFO   jTPCC : Term-00, writing per transaction results to my_result_2022-02-17_191013/data/result.csv
19:10:13,582 [main] INFO   jTPCC : Term-00, osCollectorScript=./misc/os_collector_linux.py
19:10:13,582 [main] INFO   jTPCC : Term-00, osCollectorInterval=1
19:10:13,582 [main] INFO   jTPCC : Term-00, osCollectorSSHAddr=null
19:10:13,582 [main] INFO   jTPCC : Term-00, osCollectorDevices=null
19:10:13,830 [main] INFO   jTPCC : Term-00,
19:10:14,167 [main] INFO   jTPCC : Term-00, C value for C_LAST during load: 104
19:10:14,167 [main] INFO   jTPCC : Term-00, C value for C_LAST this run:    190                          
19:21:32,141 [Thread-5] INFO   jTPCC : Term-00, 
19:21:32,141 [Thread-5] INFO   jTPCC : Term-00, Measured tpmC (NewOrders) = 7.25
19:21:32,141 [Thread-5] INFO   jTPCC : Term-00, Measured tpmTOTAL = 17.08
19:21:32,141 [Thread-5] INFO   jTPCC : Term-00, Session Start     = 2022-02-17 19:10:14
19:21:32,141 [Thread-5] INFO   jTPCC : Term-00, Session End       = 2022-02-17 19:21:32
19:21:32,141 [Thread-5] INFO   jTPCC : Term-00, Transaction Count = 192

2. 查看 OceanBase 执行计划

2.1 查询 tpcc top 5

root 用户 、oceanbase库。

[aicenter@aicenter2 ~]$  mysql -h 172.17.0.2 -uroot@obmysql -P2883 -p -c -A oceanbase
......
mysql> SELECT/*+ PARALLEL(15)*/ SQL_ID, COUNT(*) AS QPS, ROUND(AVG(elapsed_time)) avg_elapsed_time, ROUND(AVG(execute_time)) avg_exec_time FROM oceanbase.gv$sql_audit  WHERE tenant_name = 'obmysql' and db_name = 'tpcc' GROUP BY sql_id ORDER BY avg_elapsed_time DESC LIMIT 5;
+----------------------------------+------+------------------+---------------+
| SQL_ID                           | QPS  | avg_elapsed_time | avg_exec_time |
+----------------------------------+------+------------------+---------------+
| F86483FB17A84B0EA8381F4FA4EBA1AA |    1 |            93311 |         50416 |
| 3B6366A4BBB3F3DD91FEE90A15DF4C2A |    1 |            71864 |         71540 |
| 2D1366676CD073B5199DF5888FB3B0D9 |    1 |            69891 |         69420 |
| A4525988E72C9537ED712A53518E5C6F |    1 |            67603 |         67321 |
| 49E1673CDABDC24B09B1E20E10F29F55 |    1 |            64279 |         63929 |
+----------------------------------+------+------------------+---------------+
5 rows in set (0.20 sec)
# 查询 sql_id 对应的 query_sql
mysql> select distinct query_sql from oceanbase.gv$sql_audit where sql_id='F86483FB17A84B0EA8381F4FA4EBA1AA';
+--------------------------------------------------------------------------------------------+
| query_sql                                                                                  |
+--------------------------------------------------------------------------------------------+
| create table bmsql_config (
cfg_name    varchar(30) primary key,
cfg_value   varchar(50)
) |
+--------------------------------------------------------------------------------------------+
1 row in set (0.71 sec)

2.2 查看执行计划

OceanBase 数据库的执行计划命令有三种模式:EXPLAIN BASICEXPLAINEXPLAIN EXTENDED。这三种模式对执行计划展现不同粒度的细节信息:

  • EXPLAIN BASIC 命令用于最基本的计划展示。
  • EXPLAIN EXTENDED 命令用于最详细的计划展示(通常在排查问题时使用这种展示模式)。
  • EXPLAIN 命令所展示的信息可以帮助普通用户了解整个计划的执行方式。
[aicenter@aicenter2 ~]$ mysql -h 172.17.0.2 -utpcc@obmysql -P2883 -p -c -A tpcc
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 262163
Server version: 5.6.25 OceanBase 3.1.1 (r4-8c615943cbd25a6f7b8bdfd8677a13a21709a05e) (Built Oct 21 2021 10:52:05)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> explain SELECT c_first, c_middle, c_last, c_street_1, c_street_2, c_city, c_state, c_zip, c_phone, c_since, c_credit, c_credit_lim, c_discount, c_balance FROM bmsql_customer WHERE c_w_id = 2 AND c_d_id = 1 AND c_id = 1;
+-----------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                      |
+-----------------------------------------------------------------------------------------------------------------+
| ===================================================================
|ID|OPERATOR  |NAME                               |EST. ROWS|COST |
-------------------------------------------------------------------
|0 |TABLE SCAN|bmsql_customer(bmsql_customer_idx1)|30       |21167|
===================================================================

Outputs & filters: 
-------------------------------------
  0 - output([bmsql_customer.c_first], [bmsql_customer.c_middle], [bmsql_customer.c_last], [bmsql_customer.c_street_1], [bmsql_customer.c_street_2], [bmsql_customer.c_city], [bmsql_customer.c_state], [bmsql_customer.c_zip], [bmsql_customer.c_phone], [bmsql_customer.c_since], [bmsql_customer.c_credit], [bmsql_customer.c_credit_lim], [bmsql_customer.c_discount], [bmsql_customer.c_balance]), filter([bmsql_customer.c_id = 1]), 
      access([bmsql_customer.c_id], [bmsql_customer.c_first], [bmsql_customer.c_middle], [bmsql_customer.c_last], [bmsql_customer.c_street_1], [bmsql_customer.c_street_2], [bmsql_customer.c_city], [bmsql_customer.c_state], [bmsql_customer.c_zip], [bmsql_customer.c_phone], [bmsql_customer.c_since], [bmsql_customer.c_credit], [bmsql_customer.c_credit_lim], [bmsql_customer.c_discount], [bmsql_customer.c_balance]), partitions(p0)
 |
+-----------------------------------------------------------------------------------------------------------------+
1 row in set (1.31 sec)

# 最详细的计划
mysql> explain extended SELECT c_first, c_middle, c_last, c_street_1, c_street_2, c_city, c_state, c_zip, c_phone, c_since, c_credit, c_credit_lim, c_discount, c_balance FROM bmsql_customer WHERE c_w_id = 2 AND c_d_id = 1 AND c_id = 1;
+-----------------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                                     |
+-----------------------------------------------------------------------------------------------------------------+
| ===================================================================
|ID|OPERATOR  |NAME                               |EST. ROWS|COST |
-------------------------------------------------------------------
|0 |TABLE SCAN|bmsql_customer(bmsql_customer_idx1)|30       |21167|
===================================================================

Outputs & filters: 
-------------------------------------
  0 - output([bmsql_customer.c_first(0x7f9705828790)], [bmsql_customer.c_middle(0x7f9701f50ab0)], [bmsql_customer.c_last(0x7f9701f50fd0)], [bmsql_customer.c_street_1(0x7f9701f514f0)], [bmsql_customer.c_street_2(0x7f9701f51a10)], [bmsql_customer.c_city(0x7f9701f51f30)], [bmsql_customer.c_state(0x7f9701f52450)], [bmsql_customer.c_zip(0x7f9701f52af0)], [bmsql_customer.c_phone(0x7f9701f53010)], [bmsql_customer.c_since(0x7f9701f53530)], [bmsql_customer.c_credit(0x7f9701f53a50)], [bmsql_customer.c_credit_lim(0x7f9701f53f70)], [bmsql_customer.c_discount(0x7f9701f54490)], [bmsql_customer.c_balance(0x7f9701f54b30)]), filter([bmsql_customer.c_id(0x7f9705828270) = 1(0x7f9705827bf0)]), 
      access([bmsql_customer.c_id(0x7f9705828270)], [bmsql_customer.c_first(0x7f9705828790)], [bmsql_customer.c_middle(0x7f9701f50ab0)], [bmsql_customer.c_last(0x7f9701f50fd0)], [bmsql_customer.c_street_1(0x7f9701f514f0)], [bmsql_customer.c_street_2(0x7f9701f51a10)], [bmsql_customer.c_city(0x7f9701f51f30)], [bmsql_customer.c_state(0x7f9701f52450)], [bmsql_customer.c_zip(0x7f9701f52af0)], [bmsql_customer.c_phone(0x7f9701f53010)], [bmsql_customer.c_since(0x7f9701f53530)], [bmsql_customer.c_credit(0x7f9701f53a50)], [bmsql_customer.c_credit_lim(0x7f9701f53f70)], [bmsql_customer.c_discount(0x7f9701f54490)], [bmsql_customer.c_balance(0x7f9701f54b30)]), partitions(p0), 
      is_index_back=true, filter_before_indexback[false], 
      range_key([bmsql_customer.c_w_id(0x7f9701f488e0)], [bmsql_customer.c_d_id(0x7f9705827490)], [bmsql_customer.c_last(0x7f9701f50fd0)], [bmsql_customer.c_first(0x7f9705828790)], [bmsql_customer.__pk_increment(0x7f9701f56450)]), range(2,1,MIN,MIN,MIN ; 2,1,MAX,MAX,MAX), 
      range_cond([bmsql_customer.c_w_id(0x7f9701f488e0) = 2(0x7f9701f48260)], [bmsql_customer.c_d_id(0x7f9705827490) = 1(0x7f9705826e10)])

Used Hint:
-------------------------------------
  /*+
  */

Outline Data:
-------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$1" "tpcc.bmsql_customer"@"SEL$1" "bmsql_customer_idx1")
      END_OUTLINE_DATA
  */

Plan Type:
-------------------------------------
LOCAL

Optimization Info:
-------------------------------------

bmsql_customer:table_rows:8921, physical_range_rows:2991, logical_range_rows:2991, index_back_rows:2991, output_rows:29, est_method:local_storage, optimization_method=cost_based, avaiable_index_name[bmsql_customer,bmsql_customer_idx1], estimation info[table_id:1100611139453789, (table_type:1, version:0-1645096193814241-1645096193814241, logical_rc:2991, physical_rc:2991), (table_type:7, version:1645096068457973-1645107181674233-1645107183407421, logical_rc:0, physical_rc:0), (table_type:7, version:1645107183407421-1645134378804137-1645134378804137, logical_rc:0, physical_rc:0), (table_type:5, version:1645107183407421-1645134378804137-1645134378804137, logical_rc:0, physical_rc:0), (table_type:0, version:1645134378804137-1645134378804137-9223372036854775807, logical_rc:0, physical_rc:0)]
Parameters
-------------------------------------
 |
+-----------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)


3. OceanBase Outline

通过对某条 SQL 创建 Outline 可实现计划绑定。

在系统上线前,可以直接在 SQL 语句中添加 Hint,控制优化器按 Hint 指定的行为进行计划生成。

但对于已上线的业务,如果出现优化器选择的计划不够优化时,则需要在线进行计划绑定,即无需业务进行 SQL 更改,而是通过 DDL 操作将一组 Hint 加入到 SQL 中,从而使优化器根据指定的一组 Hint,对该 SQL 生成更优计划。该组 Hint 称为 Outline。

3.1 创建 Outline

OceanBase 数据库支持通过两种方式创建 Outline:

  • 一种是通过 SQL_TEXT (用户执行的带参数的原始语句)。
  • 另一种是通过 SQL_ID 创建。

注意 : 创建 Outline 需要进入对应的数据库下执行。

使用 SQL_TEXT 创建 Outline

使用 SQL_TEXT 创建 Outline 后,会生成一个 Key-Value 对存储在 Map 中,其中 Key 为绑定的 SQL 参数化后的文本,Value 为绑定的 Hint。

使用 SQL_TEXT 创建 Outline 的语法如下:

CREATE [OR REPLACE] OUTLINE <outline_name> ON <stmt> [ TO <target_stmt> ];

说明如下:

  • 指定 OR REPLACE 后,可以对已经存在执行计划进行替换。

  • 其中 stmt 一般为一个带有 Hint 和原始参数的 DML 语句。

  • 如果不指定 TO target_stmt,则表示如果数据库接受的 SQL 参数化后与 stmt 去掉 Hint 参数化文本相同,则将该 SQL 绑定 stmt 中 Hint 生成执行计划。

    如果期望对含有 Hint 的语句执行固定计划,则需要 TO target_stmt 来指明原始的 SQL。

示例:

[aicenter@aicenter2 ~]$ mysql -h 172.17.0.2 -uobuser@obmysql -P2883 -p -Dtest
Enter password: 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 53
Server version: 5.6.25 OceanBase 3.1.1 (r4-8c615943cbd25a6f7b8bdfd8677a13a21709a05e) (Built Oct 21 2021 10:52:05)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY, c2 INT, c3 INT, INDEX idx_c2(c2));
Query OK, 0 rows affected (0.23 sec)

mysql> INSERT INTO t1 VALUES(1, 1, 1), (2, 2, 2), (3, 3, 3);
Query OK, 3 rows affected (0.01 sec)
Records: 3  Duplicates: 0  Warnings: 0

# 优化器选择了走主键扫描,如果数据量增大,如果执行索引 idx_c2,该 SQL 会更优化。
# 此时可以通过创建 Outline 将该 SQL 绑定索引计划并执行。
mysql> EXPLAIN SELECT * FROM t1 WHERE c2 = 1\G;
*************************** 1. row ***************************
Query Plan: ===================================
|ID|OPERATOR  |NAME|EST. ROWS|COST|
-----------------------------------
|0 |TABLE SCAN|t1  |1        |37  |
===================================

Outputs & filters: 
-------------------------------------
  0 - output([t1.c1], [t1.c2], [t1.c3]), filter([t1.c2 = 1]), 
      access([t1.c2], [t1.c1], [t1.c3]), partitions(p0)

1 row in set (0.00 sec)

# 创建 Outline
mysql> CREATE OUTLINE otl_idx_c2 ON SELECT/*+ INDEX(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1;
Query OK, 0 rows affected (1.77 sec)

使用 SQL_ID 创建 Outline

使用 SQL_ID 创建 Outline 的语法如下:

CREATE OUTLINE outline_name ON sql_id USING HINT  hint_text;

SQL_ID 为需要绑定的 SQL 对应的 SQL_ID,可以通过以下方式获取:

  • 通过查询 gv$plan_cache_plan_stat 获取。
  • 通过查询 gv$sql 获取。
  • 通过参数化的原始 SQL,使用 MD5 生成 SQL_ID

查询 sql_id 示例:

# 查询 sql_id
[aicenter@aicenter2 ~]$ mysql -h 172.17.0.2 -uroot@obmysql -P2883 -p -c -A oceanbase
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 56
Server version: 5.6.25 OceanBase 3.1.1 (r4-8c615943cbd25a6f7b8bdfd8677a13a21709a05e) (Built Oct 21 2021 10:52:05)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> select * from gv$sql where SQL_TEXT  like 'SELECT * FROM t1 WHERE c2 = %' \G;
*************************** 1. row ***************************
               CON_ID: 1001
               SVR_IP: 127.0.0.1
             SVR_PORT: 2882
              PLAN_ID: 214
               SQL_ID: ED570339F2C856BA96008A29EDF04C74
                 TYPE: 1
             SQL_TEXT: SELECT * FROM t1 WHERE c2 = ?
      PLAN_HASH_VALUE: 8480732102453075278
      FIRST_LOAD_TIME: 2022-02-18 14:23:36.158469
     LAST_ACTIVE_TIME: 2022-02-18 14:23:36.184028
         AVG_EXE_USEC: 710788
     SLOWEST_EXE_TIME: 2022-02-18 14:23:36.184028
     SLOWEST_EXE_USEC: 710788
           SLOW_COUNT: 0
            HIT_COUNT: 0
            PLAN_SIZE: 48816
           EXECUTIONS: 1
           DISK_READS: 5
        DIRECT_WRITES: 0
          BUFFER_GETS: 22
APPLICATION_WAIT_TIME: 0
CONCURRENCY_WAIT_TIME: 0
    USER_IO_WAIT_TIME: 95072
       ROWS_PROCESSED: 1
         ELAPSED_TIME: 710788
             CPU_TIME: 615652
1 row in set (0.01 sec)
# 或者 
mysql> select * from gv$plan_cache_plan_stat where query_sql like 'SELECT * FROM t1 WHERE c2 = %' \G;
*************************** 1. row ***************************
            tenant_id: 1001
               svr_ip: 127.0.0.1
             svr_port: 2882
              plan_id: 214
               sql_id: ED570339F2C856BA96008A29EDF04C74
                 type: 1
    is_bind_sensitive: 0
        is_bind_aware: 0
                db_id: 18446744073709551615
            statement: SELECT * FROM t1 WHERE c2 = ?
            query_sql: SELECT * FROM t1 WHERE c2 = 1
       special_params: 
          param_infos: {1,0,0,0,5}
             sys_vars: 45,4194304,2,4,1,0,0,32,3,1,0,1,1,0,10485760,1,1,0,1,BINARY,BINARY,AL32UTF8,AL32UTF8,BYTE,FALSE,1,100,64,200,0,13,NULL,1,1,1
            plan_hash: 8480732102453075278
      first_load_time: 2022-02-18 14:23:36.158469
       schema_version: 1645155294956104
       merged_version: 2
     last_active_time: 2022-02-18 14:23:36.184028
         avg_exe_usec: 710788
     slowest_exe_time: 2022-02-18 14:23:36.184028
     slowest_exe_usec: 710788
           slow_count: 0
            hit_count: 0
            plan_size: 48816
           executions: 1
           disk_reads: 5
        direct_writes: 0
          buffer_gets: 22
application_wait_time: 0
concurrency_wait_time: 0
    user_io_wait_time: 95072
       rows_processed: 1
         elapsed_time: 710788
             cpu_time: 615652
         large_querys: 0
 delayed_large_querys: 0
    delayed_px_querys: 0
      outline_version: 1645155294842920
           outline_id: 1100611139404777
         outline_data: /*+ BEGIN_OUTLINE_DATA INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2") END_OUTLINE_DATA*/
         acs_sel_info: 
           table_scan: 0
            evolution: 0
       evo_executions: 0
         evo_cpu_time: 0
        timeout_count: 0
           ps_stmt_id: -1
               sessid: 0
          temp_tables: 
           is_use_jit: 0
          object_type: SQL_PLAN
           hints_info:  INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
     hints_all_worked: 1
         pl_schema_id: NULL
is_batched_multi_stmt: 0
1 row in set (0.02 sec)

mysql> exit
Bye

使用 SQL_ID 绑定 Outline,如下例所示:

[aicenter@aicenter2 ~]$ mysql -h 172.17.0.2 -uobuser@obmysql -P2883 -p -Dtest
Enter password: 
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 262165
Server version: 5.6.25 OceanBase 3.1.1 (r4-8c615943cbd25a6f7b8bdfd8677a13a21709a05e) (Built Oct 21 2021 10:52:05)

Copyright (c) 2000, 2021, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

# 限制并发为 1 
mysql> CREATE OUTLINE otl2_idx_c2 ON "ED570339F2C856BA96008A29EDF04C74" USING HINT /*+ parallel(1)*/ ;
Query OK, 0 rows affected (0.04 sec)


Outline Data 是优化器为了完全复现某一计划而生成的一组 Hint 信息,以 BEGIN_OUTLINE_DATA 开始,并以 END_OUTLINE_DATA 结束。

Outline Data 可以通过 EXPLAIN EXTENDED 命令获得,如下例所示:

mysql> EXPLAIN EXTENDED SELECT/*+ index(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1\G;
*************************** 1. row ***************************
Query Plan: =========================================
|ID|OPERATOR  |NAME      |EST. ROWS|COST|
-----------------------------------------
|0 |TABLE SCAN|t1(idx_c2)|1        |88  |
=========================================

Outputs & filters: 
-------------------------------------
  0 - output([t1.c1(0x7f96cbc98f70)], [t1.c2(0x7f96cbc98ce0)], [t1.c3(0x7f96cbc99200)]), filter(nil), 
      access([t1.c2(0x7f96cbc98ce0)], [t1.c1(0x7f96cbc98f70)], [t1.c3(0x7f96cbc99200)]), partitions(p0), 
      is_index_back=true, 
      range_key([t1.c2(0x7f96cbc98ce0)], [t1.c1(0x7f96cbc98f70)]), range(1,MIN ; 1,MAX), 
      range_cond([t1.c2(0x7f96cbc98ce0) = 1(0x7f96cbc98660)])

Used Hint:
-------------------------------------
  /*+
      INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
  */

Outline Data:
-------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
      END_OUTLINE_DATA
  */

Plan Type:
-------------------------------------
LOCAL

Optimization Info:
-------------------------------------

t1:table_rows:3, physical_range_rows:1, logical_range_rows:1, index_back_rows:1, output_rows:1, est_method:local_storage, optimization_method=cost_based, avaiable_index_name[idx_c2], pruned_index_name[t1], estimation info[table_id:1100611139453792, (table_type:1, version:0-1645161295182407-1645161295182407, logical_rc:1, physical_rc:1), (table_type:7, version:1645161285065011-1645161295182407-1645161316877637, logical_rc:0, physical_rc:0), (table_type:5, version:1645161285065011-1645161295182407-1645161316877637, logical_rc:0, physical_rc:0), (table_type:0, version:1645161316877637-1645161316877637-9223372036854775807, logical_rc:0, physical_rc:0)]
Parameters
-------------------------------------

1 row in set (0.00 sec)

Outline Data 也属于 Hint,因此可以用在计划绑定的过程中,如下例所示:

mysql> CREATE OUTLINE otl3_idx_c2 ON "ED570339F2C856BA96008A29EDF04C74" USING HINT 
    -> /*+
    ->       BEGIN_OUTLINE_DATA
    ->       INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2")
    ->       END_OUTLINE_DATA
    ->   */
    -> ;
ERROR 5264 (HY000): Outline '' already exists
mysql> 

3.2 确定 Outline 创建生效

确定创建的 Outline 是否成功且符合预期,需要进行如下三步的验证:

  1. 确定 Outline 创建成功。

    通过查看 gv$outline 视图,确认是否成功创建对应名称的 Outline。

mysql> SELECT * FROM oceanbase.gv$outline WHERE OUTLINE_NAME = 'otl_idx_c2'\G;
*************************** 1. row ***************************
        tenant_id: 1001
      database_id: 1100611139404776
       outline_id: 1100611139404777
    database_name: test
     outline_name: otl_idx_c2
visible_signature: SELECT * FROM t1 WHERE c2 = ?
         sql_text: SELECT/*+ INDEX(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1
   outline_target: 
      outline_sql: SELECT /*+ BEGIN_OUTLINE_DATA INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2") END_OUTLINE_DATA*/* FROM t1 WHERE c2 = 1

  1. 确定新的 SQL 是否通过绑定的 Outline 生成了新执行计划。

    当绑定 Outline 的 SQL 执行新的查询后,查询 gv$plan_cache_plan_stat 表中该 SQL 对应的计划信息中的 outline_id。如果 outline_id 与在 gv$outline 中查到的 outline_id 相同,则表示是按绑定的 Outline 生成的执行计划,否则不是。

    mysql> SELECT SQL_ID, PLAN_ID, STATEMENT, OUTLINE_ID, OUTLINE_DATA FROM oceanbase.gv$plan_cache_plan_stat WHERE STATEMENT LIKE '%SELECT * FROM t1 WHERE c2 =%'\G
    *************************** 1. row ***************************
          SQL_ID: ED570339F2C856BA96008A29EDF04C74
         PLAN_ID: 214
       STATEMENT: SELECT * FROM t1 WHERE c2 = ?
      OUTLINE_ID: 1100611139404777
    OUTLINE_DATA: /*+ BEGIN_OUTLINE_DATA INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2") END_OUTLINE_DATA*/
    
    # 查询gv$outline
    mysql> select * from gv$outline where outline_name = 'otl_idx_c2' \G;
    *************************** 1. row ***************************
            tenant_id: 1001
          database_id: 1100611139404776
           outline_id: 1100611139404777
        database_name: test
         outline_name: otl_idx_c2
    visible_signature: SELECT * FROM t1 WHERE c2 = ?
             sql_text: SELECT/*+ INDEX(t1 idx_c2)*/ * FROM t1 WHERE c2 = 1
       outline_target: 
          outline_sql: SELECT /*+ BEGIN_OUTLINE_DATA INDEX(@"SEL$1" "test.t1"@"SEL$1" "idx_c2") END_OUTLINE_DATA*/* FROM t1 WHERE c2 = 1
          
    # out line 未生效
    # CREATE OUTLINE otl2_idx_c2 ON "ED570339F2C856BA96008A29EDF04C74" USING HINT /*+ parallel(1)*/ ;
    mysql> select * from gv$outline where outline_name = 'otl2_idx_c2' \G;
    *************************** 1. row ***************************
            tenant_id: 1001
          database_id: 1100611139404776
           outline_id: 1100611139404778
        database_name: test
         outline_name: otl2_idx_c2
    visible_signature: 
             sql_text: 
       outline_target: 
          outline_sql: 
    1 row in set (0.01 sec)
    
    # 使用SQL语句创建outline
    mysql> CREATE OUTLINE otl3_idx_c2 ON SELECT /*+ parallel(1)*/ * FROM t1 WHERE c2 = 1;
    Query OK, 0 rows affected (0.06 sec)
    
    # 查看是否生效
    mysql> select * from gv$outline where outline_name = 'otl3_idx_c2' \G;
    *************************** 1. row ***************************
            tenant_id: 1001
          database_id: 1100611139404776
           outline_id: 1100611139404779
        database_name: test
         outline_name: otl3_idx_c2
    visible_signature: SELECT  * FROM t1 WHERE c2 = ?
             sql_text: SELECT /*+ parallel(1)*/ * FROM t1 WHERE c2 = 1
       outline_target: 
          outline_sql: SELECT /*+ BEGIN_OUTLINE_DATA FULL(@"SEL$1" "test.t1"@"SEL$1") PARALLEL(1) END_OUTLINE_DATA*/ * FROM t1 WHERE c2 = 1
    1 row in set (0.00 sec)
    
    
    1. 确定生成的执行计划是否符合预期。

      确定是通过绑定的 Outline 生成的计划后,需要确定生成的计划是否符合预期,可以通过查询 gv$plan_cache_plan_stat 表查看 plan_cache 中缓存的执行计划形状。

3.3 删除 Outline

删除 Outline 后,对应 SQL 将不再依据所绑定的 Outline 重新生成执行计划。

删除 Outline 的语法如下:

DROP OUTLINE outline_name;

删除前面创建的 outline:

mysql> DROP OUTLINE otl_idx_c2;
Query OK, 0 rows affected (0.06 sec)

mysql> DROP OUTLINE otl2_idx_c2;
Query OK, 0 rows affected (0.01 sec)

mysql> DROP OUTLINE otl3_idx_c2;
Query OK, 0 rows affected (0.02 sec)

查看 oceanbase.gv$outline,确认是否删除outline:

mysql> SELECT * FROM oceanbase.gv$outline;
Empty set (0.00 sec)

删除 Outline 需要在 outline_name 中指定 Database 名,或者在 USE DATABASE 命令后执行删除操作。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值