开启少量并行后执行效率提升100倍,如何理解?

【 使用环境 】生产环境 or 测试环境
【 OB or 其他组件 】OB
【 使用版本 】5.7.25-OceanBase_CE-v4.2.0.0
【问题描述】
SQL1=select /*+ parallel(2) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;

SQL2=select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
快100倍!
【复现路径】
TPCH10
表结构:

obclient [tpch10]> show create table nation\G
*************************** 1. row ***************************
       Table: nation
Create Table: CREATE TABLE `nation` (
  `N_NATIONKEY` bigint(20) NOT NULL,
  `N_NAME` char(25) NOT NULL,
  `N_REGIONKEY` bigint(20) NOT NULL,
  `N_COMMENT` varchar(152) DEFAULT NULL,
  PRIMARY KEY (`N_NATIONKEY`)
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
1 row in set (0.004 sec)

obclient [tpch10]> show create table customer \G
*************************** 1. row ***************************
       Table: customer
Create Table: CREATE TABLE `customer` (
  `C_CUSTKEY` bigint(20) NOT NULL,
  `C_NAME` varchar(25) NOT NULL,
  `C_ADDRESS` varchar(40) NOT NULL,
  `C_NATIONKEY` bigint(20) NOT NULL,
  `C_PHONE` char(15) NOT NULL,
  `C_ACCTBAL` decimal(15,2) NOT NULL,
  `C_MKTSEGMENT` char(10) NOT NULL,
  `C_COMMENT` varchar(117) NOT NULL,
  PRIMARY KEY (`C_CUSTKEY`),
  KEY `idx1` (`C_NAME`) BLOCK_SIZE 16384 LOCAL,
  KEY `idx2` (`C_ACCTBAL`) BLOCK_SIZE 16384 LOCAL,
  KEY `idx3` (`C_NATIONKEY`) BLOCK_SIZE 16384 LOCAL
) DEFAULT CHARSET = utf8mb4 ROW_FORMAT = DYNAMIC COMPRESSION = 'zstd_1.3.8' REPLICA_NUM = 1 BLOCK_SIZE = 16384 USE_BLOOM_FILTER = FALSE TABLET_SIZE = 134217728 PCTFREE = 0
1 row in set (0.003 sec)

在测试过程中不开并行SQL1的执行时间为3秒(多次重复执行),开并行SQL2的执行时间为0.04秒,应该如何理解呢?

SQL1的执行计划如下:

obclient [tpch10]> explain extended select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+-----------------------------------------------------------------------------------------------------+
| Query Plan                                                                                          |
+-----------------------------------------------------------------------------------------------------+
| ===================================================================                                 |
| |ID|OPERATOR                        |NAME   |EST.ROWS|EST.TIME(us)|                                 |
| -------------------------------------------------------------------                                 |
| |0 |SCALAR GROUP BY                 |       |1       |978495      |                                 |
| |1 |└─NESTED-LOOP JOIN              |       |12500000|751945      |                                 |
| |2 |  ├─TABLE FULL SCAN             |b      |25      |5           |                                 |
| |3 |  └─DISTRIBUTED TABLE RANGE SCAN|a(idx3)|500000  |17608       |                                 |
| ===================================================================                                 |
| Outputs & filters:                                                                                  |
| -------------------------------------                                                               |
|   0 - output([T_FUN_COUNT(*)(0x7f1a2e040760)]), filter(nil), rowset=256                             |
|       group(nil), agg_func([T_FUN_COUNT(*)(0x7f1a2e040760)])                                        |
|   1 - output(nil), filter(nil), rowset=256                                                          |
|       conds(nil), nl_params_([b.N_NATIONKEY(0x7f1a2e040200)(:1)]), use_batch=true                   |
|   2 - output([b.N_NATIONKEY(0x7f1a2e040200)]), filter(nil), rowset=256                              |
|       access([b.N_NATIONKEY(0x7f1a2e040200)]), partitions(p0)                                       |
|       is_index_back=false, is_global_index=false,                                                   |
|       range_key([b.N_NATIONKEY(0x7f1a2e040200)]), range(MIN ; MAX)always true                       |
|   3 - output(nil), filter(nil), rowset=256                                                          |
|       access([GROUP_ID(0x7f1a2e0f86d0)]), partitions(p0)                                            |
|       is_index_back=false, is_global_index=false,                                                   |
|       range_key([a.C_NATIONKEY(0x7f1a2e03ff20)], [a.C_CUSTKEY(0x7f1a2e040d80)]), range(MIN ; MAX),  |
|       range_cond([a.C_NATIONKEY(0x7f1a2e03ff20) < :1(0x7f1a2e0cb960)])                              |
| Used Hint:                                                                                          |
| -------------------------------------                                                               |
|   /*+                                                                                               |
|                                                                                                     |
|       PARALLEL(1)                                                                                   |
|   */                                                                                                |
| Qb name trace:                                                                                      |
| -------------------------------------                                                               |
|   stmt_id:0, stmt_type:T_EXPLAIN                                                                    |
|   stmt_id:1, SEL$1 > SEL$C6D21C0F                                                                   |
| Outline Data:                                                                                       |
| -------------------------------------                                                               |
|   /*+                                                                                               |
|       BEGIN_OUTLINE_DATA                                                                            |
|       LEADING(@"SEL$C6D21C0F" ("tpch10"."b"@"SEL$1" "tpch10"."a"@"SEL$1"))                          |
|       USE_NL(@"SEL$C6D21C0F" "tpch10"."a"@"SEL$1")                                                  |
|       FULL(@"SEL$C6D21C0F" "b"@"SEL$1")                                                             |
|       INDEX(@"SEL$C6D21C0F" "a"@"SEL$1" "idx3")                                                     |
|       USE_DAS(@"SEL$C6D21C0F" "a"@"SEL$1")                                                          |
|       OUTER_TO_INNER(@"SEL$1")                                                                      |
|       PARALLEL(1)                                                                                   |
|       OPTIMIZER_FEATURES_ENABLE('4.0.0.0')                                                          |
|       END_OUTLINE_DATA                                                                              |
|   */                                                                                                |
| Optimization Info:                                                                                  |
| -------------------------------------                                                               |
|   b:                                                                                                |
|       table_rows:25                                                                                 |
|       physical_range_rows:25                                                                        |
|       logical_range_rows:25                                                                         |
|       index_back_rows:0                                                                             |
|       output_rows:25                                                                                |
|       table_dop:1                                                                                   |
|       dop_method:Global DOP                                                                         |
|       avaiable_index_name:[nation]                                                                  |
|       stats version:1694254794515646                                                                |
|       dynamic sampling level:0                                                                      |
|   a:                                                                                                |
|       table_rows:1500000                                                                            |
|       physical_range_rows:500000                                                                    |
|       logical_range_rows:500000                                                                     |
|       index_back_rows:0                                                                             |
|       output_rows:500000                                                                            |
|       table_dop:1                                                                                   |
|       dop_method:DAS DOP                                                                            |
|       avaiable_index_name:[idx1, idx2, idx3, customer]                                              |
|       pruned_index_name:[idx1, idx2, customer]                                                      |
|       stats version:1694254801441111                                                                |
|       dynamic sampling level:0                                                                      |
|   Plan Type:                                                                                        |
|       LOCAL                                                                                         |
|   Note:                                                                                             |
|       Degree of Parallelism is 1 because of hint                                                    |
+-----------------------------------------------------------------------------------------------------+
76 rows in set (0.004 sec)

SQL1的执行时间为:

obclient [tpch10]> select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (3.413 sec)

SQL1的SQL_AUDIT信息为:

                         SVR_IP: 192.168.31.201
                       SVR_PORT: 2882
                     REQUEST_ID: 431213
                    SQL_EXEC_ID: 4261706
                       TRACE_ID: YB42C0A81FC9-0006059EDF40460A-0-0
                            SID: 3221509816
                      CLIENT_IP: 192.168.31.201
                    CLIENT_PORT: 54870
                      TENANT_ID: 1004
                    TENANT_NAME: tpch
            EFFECTIVE_TENANT_ID: 1004
                        USER_ID: 200001
                      USER_NAME: root
                     USER_GROUP: 0
                 USER_CLIENT_IP: 192.168.31.200
                          DB_ID: 500523
                        DB_NAME: tpch10
                         SQL_ID: 7C6D34D0C862BF99E674CE42A638C2FF
                      QUERY_SQL: select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey
                        PLAN_ID: 419
                  AFFECTED_ROWS: 0
                    RETURN_ROWS: 1
                  PARTITION_CNT: 2
                       RET_CODE: 0
                          QC_ID: 0
                         DFO_ID: 0
                         SQC_ID: 0
                      WORKER_ID: 0
                          EVENT: 
                         P1TEXT: 
                             P1: 0
                         P2TEXT: 
                             P2: 0
                         P3TEXT: 
                             P3: 0
                          LEVEL: 0
                  WAIT_CLASS_ID: 100
                    WAIT_CLASS#: 0
                     WAIT_CLASS: OTHER
                          STATE: MAX_WAIT TIME ZERO
                WAIT_TIME_MICRO: 0
          TOTAL_WAIT_TIME_MICRO: 0
                    TOTAL_WAITS: 0
                      RPC_COUNT: 0
                      PLAN_TYPE: 1
                   IS_INNER_SQL: 0
                IS_EXECUTOR_RPC: 0
                    IS_HIT_PLAN: 0
                   REQUEST_TIME: 1695189590729929
                   ELAPSED_TIME: 3412135
                       NET_TIME: 0
                  NET_WAIT_TIME: 2
                     QUEUE_TIME: 44
                    DECODE_TIME: 1
                  GET_PLAN_TIME: 2174
                   EXECUTE_TIME: 3409895
          APPLICATION_WAIT_TIME: 0
          CONCURRENCY_WAIT_TIME: 0
              USER_IO_WAIT_TIME: 0
                  SCHEDULE_TIME: 0
                  ROW_CACHE_HIT: 0
         BLOOM_FILTER_CACHE_HIT: 0
                BLOCK_CACHE_HIT: 2343
                     DISK_READS: 0
                      RETRY_CNT: 0
                     TABLE_SCAN: 1
              CONSISTENCY_LEVEL: 3
        MEMSTORE_READ_ROW_COUNT: 0
         SSSTORE_READ_ROW_COUNT: 18002442
            DATA_BLOCK_READ_CNT: 2563
           DATA_BLOCK_CACHE_HIT: 2563
           INDEX_BLOCK_READ_CNT: 62
          INDEX_BLOCK_CACHE_HIT: 36
            BLOCKSCAN_BLOCK_CNT: 0
              BLOCKSCAN_ROW_CNT: 0
PUSHDOWN_STORAGE_FILTER_ROW_CNT: 0
            REQUEST_MEMORY_USED: 654232
          EXPECTED_WORKER_COUNT: 0
              USED_WORKER_COUNT: 0
                     SCHED_INFO: NULL
             FUSE_ROW_CACHE_HIT: 0
              PS_CLIENT_STMT_ID: -1
               PS_INNER_STMT_ID: -1
                          TX_ID: 0
               SNAPSHOT_VERSION: 1695189590732174706
                   REQUEST_TYPE: 2
          IS_BATCHED_MULTI_STMT: 0
                  OB_TRACE_INFO: NULL
                      PLAN_HASH: 10268919862084901393
             LOCK_FOR_READ_TIME: 0
                   PARAMS_VALUE: 
                      RULE_NAME: 
                  PARTITION_HIT: 1
            TX_INTERNAL_ROUTING: 0
               TX_STATE_VERSION: 0

SQL2的执行计划如下:

obclient [tpch10]> explain extended select /*+ parallel(2) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------------------------------------------------------------------------------------------------------+
| Query Plan                                                                                               |
+----------------------------------------------------------------------------------------------------------+
| ============================================================================                             |
| |ID|OPERATOR                                |NAME    |EST.ROWS|EST.TIME(us)|                             |
| ----------------------------------------------------------------------------                             |
| |0 |SCALAR GROUP BY                         |        |1       |301288      |                             |
| |1 |└─PX COORDINATOR                        |        |2       |301288      |                             |
| |2 |  └─EXCHANGE OUT DISTR                  |:EX10001|2       |301287      |                             |
| |3 |    └─MERGE GROUP BY                    |        |2       |301287      |                             |
| |4 |      └─NESTED-LOOP JOIN                |        |12500000|188012      |                             |
| |5 |        ├─EXCHANGE IN DISTR             |        |25      |11          |                             |
| |6 |        │ └─EXCHANGE OUT DISTR (BC2HOST)|:EX10000|25      |8           |                             |
| |7 |        │   └─PX BLOCK ITERATOR         |        |25      |3           |                             |
| |8 |        │     └─TABLE FULL SCAN         |b       |25      |3           |                             |
| |9 |        └─PX PARTITION ITERATOR         |        |500000  |8805        |                             |
| |10|          └─TABLE RANGE SCAN            |a(idx3) |500000  |8805        |                             |
| ============================================================================                             |
| Outputs & filters:                                                                                       |
| -------------------------------------                                                                    |
|   0 - output([T_FUN_COUNT_SUM(T_FUN_COUNT(*)(0x7f1a4be40760))(0x7f1a4bf00300)]), filter(nil), rowset=256 |
|       group(nil), agg_func([T_FUN_COUNT_SUM(T_FUN_COUNT(*)(0x7f1a4be40760))(0x7f1a4bf00300)])            |
|   1 - output([T_FUN_COUNT(*)(0x7f1a4be40760)]), filter(nil), rowset=256                                  |
|   2 - output([T_FUN_COUNT(*)(0x7f1a4be40760)]), filter(nil), rowset=256                                  |
|       dop=2                                                                                              |
|   3 - output([T_FUN_COUNT(*)(0x7f1a4be40760)]), filter(nil), rowset=256                                  |
|       group(nil), agg_func([T_FUN_COUNT(*)(0x7f1a4be40760)])                                             |
|   4 - output(nil), filter(nil), rowset=256                                                               |
|       conds(nil), nl_params_([b.N_NATIONKEY(0x7f1a4be40200)(:1)]), use_batch=false                       |
|   5 - output([b.N_NATIONKEY(0x7f1a4be40200)]), filter(nil), rowset=256                                   |
|   6 - output([b.N_NATIONKEY(0x7f1a4be40200)]), filter(nil), rowset=256                                   |
|       dop=2                                                                                              |
|   7 - output([b.N_NATIONKEY(0x7f1a4be40200)]), filter(nil), rowset=256                                   |
|   8 - output([b.N_NATIONKEY(0x7f1a4be40200)]), filter(nil), rowset=256                                   |
|       access([b.N_NATIONKEY(0x7f1a4be40200)]), partitions(p0)                                            |
|       is_index_back=false, is_global_index=false,                                                        |
|       range_key([b.N_NATIONKEY(0x7f1a4be40200)]), range(MIN ; MAX)always true                            |
|   9 - output(nil), filter(nil), rowset=256                                                               |
|       access all                                                                                         |
|  10 - output(nil), filter(nil), rowset=256                                                               |
|       access(nil), partitions(p0)                                                                        |
|       is_index_back=false, is_global_index=false,                                                        |
|       range_key([a.C_NATIONKEY(0x7f1a4be3ff20)], [a.C_CUSTKEY(0x7f1a4be40d80)]), range(MIN ; MAX),       |
|       range_cond([a.C_NATIONKEY(0x7f1a4be3ff20) < :1(0x7f1a4beca720)])                                   |
| Used Hint:                                                                                               |
| -------------------------------------                                                                    |
|   /*+                                                                                                    |
|                                                                                                          |
|       PARALLEL(2)                                                                                        |
|   */                                                                                                     |
| Qb name trace:                                                                                           |
| -------------------------------------                                                                    |
|   stmt_id:0, stmt_type:T_EXPLAIN                                                                         |
|   stmt_id:1, SEL$1 > SEL$C6D21C0F                                                                        |
| Outline Data:                                                                                            |
| -------------------------------------                                                                    |
|   /*+                                                                                                    |
|       BEGIN_OUTLINE_DATA                                                                                 |
|       GBY_PUSHDOWN(@"SEL$C6D21C0F")                                                                      |
|       LEADING(@"SEL$C6D21C0F" ("tpch10"."b"@"SEL$1" "tpch10"."a"@"SEL$1"))                               |
|       USE_NL(@"SEL$C6D21C0F" "tpch10"."a"@"SEL$1")                                                       |
|       PQ_DISTRIBUTE(@"SEL$C6D21C0F" "tpch10"."a"@"SEL$1" BC2HOST NONE)                                   |
|       PARALLEL(@"SEL$C6D21C0F" "b"@"SEL$1" 2)                                                            |
|       FULL(@"SEL$C6D21C0F" "b"@"SEL$1")                                                                  |
|       PARALLEL(@"SEL$C6D21C0F" "a"@"SEL$1" 2)                                                            |
|       INDEX(@"SEL$C6D21C0F" "a"@"SEL$1" "idx3")                                                          |
|       OUTER_TO_INNER(@"SEL$1")                                                                           |
|       PARALLEL(2)                                                                                        |
|       OPTIMIZER_FEATURES_ENABLE('4.0.0.0')                                                               |
|       END_OUTLINE_DATA                                                                                   |
|   */                                                                                                     |
| Optimization Info:                                                                                       |
| -------------------------------------                                                                    |
|   b:                                                                                                     |
|       table_rows:25                                                                                      |
|       physical_range_rows:25                                                                             |
|       logical_range_rows:25                                                                              |
|       index_back_rows:0                                                                                  |
|       output_rows:25                                                                                     |
|       table_dop:2                                                                                        |
|       dop_method:Global DOP                                                                              |
|       avaiable_index_name:[nation]                                                                       |
|       stats version:1694254794515646                                                                     |
|       dynamic sampling level:0                                                                           |
|   a:                                                                                                     |
|       table_rows:1500000                                                                                 |
|       physical_range_rows:500000                                                                         |
|       logical_range_rows:500000                                                                          |
|       index_back_rows:0                                                                                  |
|       output_rows:500000                                                                                 |
|       table_dop:2                                                                                        |
|       dop_method:Global DOP                                                                              |
|       avaiable_index_name:[idx1, idx2, idx3, customer]                                                   |
|       pruned_index_name:[idx1, idx2, customer]                                                           |
|       stats version:1694254801441111                                                                     |
|       dynamic sampling level:0                                                                           |
|   Plan Type:                                                                                             |
|       DISTRIBUTED                                                                                        |
|   Note:                                                                                                  |
|       Degree of Parallelism is 2 because of hint                                                         |
+----------------------------------------------------------------------------------------------------------+
97 rows in set (0.004 sec)

SQL2的执行时间为:

obclient [tpch10]> select /*+ parallel(2) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (0.046 sec)

SQL2的SQL_AUDIT信息为:

                         SVR_IP: 192.168.31.201
                       SVR_PORT: 2882
                     REQUEST_ID: 431023
                    SQL_EXEC_ID: 4259502
                       TRACE_ID: YB42C0A81FC9-0006059EDF404608-0-0
                            SID: 3221509816
                      CLIENT_IP: 192.168.31.201
                    CLIENT_PORT: 54870
                      TENANT_ID: 1004
                    TENANT_NAME: tpch
            EFFECTIVE_TENANT_ID: 1004
                        USER_ID: 200001
                      USER_NAME: root
                     USER_GROUP: 0
                 USER_CLIENT_IP: 192.168.31.200
                          DB_ID: 500523
                        DB_NAME: tpch10
                         SQL_ID: BBAC7887A3247003B0456DFF9CCD54E1
                      QUERY_SQL: select /*+ parallel(2) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey
                        PLAN_ID: 417
                  AFFECTED_ROWS: 0
                    RETURN_ROWS: 1
                  PARTITION_CNT: 2
                       RET_CODE: 0
                          QC_ID: 0
                         DFO_ID: 0
                         SQC_ID: 0
                      WORKER_ID: 0
                          EVENT: px loop condition wait
                         P1TEXT: address
                             P1: 139750419651280
                         P2TEXT: 
                             P2: 0
                         P3TEXT: 
                             P3: 0
                          LEVEL: 0
                  WAIT_CLASS_ID: 104
                    WAIT_CLASS#: 4
                     WAIT_CLASS: CONCURRENCY
                          STATE: WAITED SHORT TIME
                WAIT_TIME_MICRO: 1589
          TOTAL_WAIT_TIME_MICRO: 41615
                    TOTAL_WAITS: 38
                      RPC_COUNT: 0
                      PLAN_TYPE: 3
                   IS_INNER_SQL: 0
                IS_EXECUTOR_RPC: 0
                    IS_HIT_PLAN: 0
                   REQUEST_TIME: 1695189577202586
                   ELAPSED_TIME: 45293
                       NET_TIME: 0
                  NET_WAIT_TIME: 3
                     QUEUE_TIME: 45
                    DECODE_TIME: 1
                  GET_PLAN_TIME: 2271
                   EXECUTE_TIME: 42955
          APPLICATION_WAIT_TIME: 0
          CONCURRENCY_WAIT_TIME: 0
              USER_IO_WAIT_TIME: 0
                  SCHEDULE_TIME: 0
                  ROW_CACHE_HIT: 0
         BLOOM_FILTER_CACHE_HIT: 0
                BLOCK_CACHE_HIT: 0
                     DISK_READS: 0
                      RETRY_CNT: 0
                     TABLE_SCAN: 1
              CONSISTENCY_LEVEL: 3
        MEMSTORE_READ_ROW_COUNT: 0
         SSSTORE_READ_ROW_COUNT: 0
            DATA_BLOCK_READ_CNT: 0
           DATA_BLOCK_CACHE_HIT: 0
           INDEX_BLOCK_READ_CNT: 0
          INDEX_BLOCK_CACHE_HIT: 0
            BLOCKSCAN_BLOCK_CNT: 0
              BLOCKSCAN_ROW_CNT: 0
PUSHDOWN_STORAGE_FILTER_ROW_CNT: 0
            REQUEST_MEMORY_USED: 82578688
          EXPECTED_WORKER_COUNT: 4
              USED_WORKER_COUNT: 4
                     SCHED_INFO: NULL
             FUSE_ROW_CACHE_HIT: 0
              PS_CLIENT_STMT_ID: -1
               PS_INNER_STMT_ID: -1
                          TX_ID: 0
               SNAPSHOT_VERSION: 1695189577204943341
                   REQUEST_TYPE: 2
          IS_BATCHED_MULTI_STMT: 0
                  OB_TRACE_INFO: NULL
                      PLAN_HASH: 2276062942640480755
             LOCK_FOR_READ_TIME: 0
                   PARAMS_VALUE: 
                      RULE_NAME: 
                  PARTITION_HIT: 1
            TX_INTERNAL_ROUTING: 0
               TX_STATE_VERSION: 0

从执行计划上没有看出来开启并发后有什么特别之处,只是多了一个开启并行正常的exchange(BC2HOST)算子,但是看SQL_AUDIT parallel=2的情况下SSSTORE_READ_ROW_COUNT竟然为0,(parallel=1的情况下是18002442),也就是开启并行后都不需要进行行读了,这个如何理解?

2 个赞

3s 和 0.04s 都太小,数据规模(TPCH 10)也太小,容易有测量误差。
何不把数据量翻个 100倍或1000倍 看看呢。那时候执行计划稳定一些,结果对比也更有说服力一些。

1 个赞

数据库这么严谨,不可能有一百倍的误差吧?而且不开并行是非常稳定的3秒多,开了并行是非常稳定的0.04秒左右,这是多次测试的结果。我认为这并不是误差导致。

1 个赞

可以看下并行DML:https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000034035
https://www.oceanbase.com/docs/common-oceanbase-database-cn-1000000000034041

有差异是肯定的,只是也觉得 百倍 差异太大。所以建议你扩大数据量后对比,然后大家再继续分析。毕竟你想分析的是一个 AP 场景。做实验先把数据量搞大一点,后面大家分析的结论可靠性和可信性都高一些。

你好,这块也是看过的。但是没想明白为何有这么大的差距。

开并行就是批量的插入或者更新,删除,可以有效的提高执行效率,
开并行和不开并行,你可以扩大数据量再对比一下。

我分析并且验证了下,这个问题主要是use_batch=true的情况下效率较低导致。
默认_NLJ_BATCHING_ENABLED这个参数是true的,当不开并行时候NLJ是可以用到左表一次取一批数据然后右表取匹配。应该是开启并行后NLJ不支持use_batch,看执行计划中use_batch=false。
我在不开启并行的情况下尝试关闭use_batch,执行效率就非常高了,符合了预期:

obclient [tpch10]> SET _NLJ_BATCHING_ENABLED=false;
Query OK, 0 rows affected (0.001 sec)

obclient [tpch10]> select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (0.073 sec)

obclient [tpch10]> explain extended select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+-----------------------------------------------------------------------------------------------------+
| Query Plan                                                                                          |
+-----------------------------------------------------------------------------------------------------+
| ===================================================================                                 |
| |ID|OPERATOR                        |NAME   |EST.ROWS|EST.TIME(us)|                                 |
| -------------------------------------------------------------------                                 |
| |0 |SCALAR GROUP BY                 |       |1       |978560      |                                 |
| |1 |└─NESTED-LOOP JOIN              |       |12500000|752010      |                                 |
| |2 |  ├─TABLE FULL SCAN             |b      |25      |5           |                                 |
| |3 |  └─DISTRIBUTED TABLE RANGE SCAN|a(idx3)|500000  |17610       |                                 |
| ===================================================================                                 |
| Outputs & filters:                                                                                  |
| -------------------------------------                                                               |
|   0 - output([T_FUN_COUNT(*)(0x7f1a37c40760)]), filter(nil), rowset=256                             |
|       group(nil), agg_func([T_FUN_COUNT(*)(0x7f1a37c40760)])                                        |
|   1 - output(nil), filter(nil), rowset=256                                                          |
|       conds(nil), nl_params_([b.N_NATIONKEY(0x7f1a37c40200)(:1)]), use_batch=false                  |
|   2 - output([b.N_NATIONKEY(0x7f1a37c40200)]), filter(nil), rowset=256                              |
|       access([b.N_NATIONKEY(0x7f1a37c40200)]), partitions(p0)                                       |
|       is_index_back=false, is_global_index=false,                                                   |
|       range_key([b.N_NATIONKEY(0x7f1a37c40200)]), range(MIN ; MAX)always true                       |
|   3 - output(nil), filter(nil), rowset=256                                                          |
|       access(nil), partitions(p0)                                                                   |
|       is_index_back=false, is_global_index=false,                                                   |
|       range_key([a.C_NATIONKEY(0x7f1a37c3ff20)], [a.C_CUSTKEY(0x7f1a37c40d80)]), range(MIN ; MAX),  |
|       range_cond([a.C_NATIONKEY(0x7f1a37c3ff20) < :1(0x7f1a37ccb960)])                              |
| Used Hint:                                                                                          |
| -------------------------------------                                                               |
|   /*+                                                                                               |
|                                                                                                     |
|       PARALLEL(1)                                                                                   |
|   */                                                                                                |
| Qb name trace:                                                                                      |
| -------------------------------------                                                               |
|   stmt_id:0, stmt_type:T_EXPLAIN                                                                    |
|   stmt_id:1, SEL$1 > SEL$C6D21C0F                                                                   |
| Outline Data:                                                                                       |
| -------------------------------------                                                               |
|   /*+                                                                                               |
|       BEGIN_OUTLINE_DATA                                                                            |
|       LEADING(@"SEL$C6D21C0F" ("tpch10"."b"@"SEL$1" "tpch10"."a"@"SEL$1"))                          |
|       USE_NL(@"SEL$C6D21C0F" "tpch10"."a"@"SEL$1")                                                  |
|       FULL(@"SEL$C6D21C0F" "b"@"SEL$1")                                                             |
|       INDEX(@"SEL$C6D21C0F" "a"@"SEL$1" "idx3")                                                     |
|       USE_DAS(@"SEL$C6D21C0F" "a"@"SEL$1")                                                          |
|       OUTER_TO_INNER(@"SEL$1")                                                                      |
|       PARALLEL(1)                                                                                   |
|       OPTIMIZER_FEATURES_ENABLE('4.0.0.0')                                                          |
|       END_OUTLINE_DATA                                                                              |
|   */                                                                                                |
| Optimization Info:                                                                                  |
| -------------------------------------                                                               |
|   b:                                                                                                |
|       table_rows:25                                                                                 |
|       physical_range_rows:25                                                                        |
|       logical_range_rows:25                                                                         |
|       index_back_rows:0                                                                             |
|       output_rows:25                                                                                |
|       table_dop:1                                                                                   |
|       dop_method:Global DOP                                                                         |
|       avaiable_index_name:[nation]                                                                  |
|       stats version:1694254794515646                                                                |
|       dynamic sampling level:0                                                                      |
|   a:                                                                                                |
|       table_rows:1500000                                                                            |
|       physical_range_rows:500000                                                                    |
|       logical_range_rows:500000                                                                     |
|       index_back_rows:0                                                                             |
|       output_rows:500000                                                                            |
|       table_dop:1                                                                                   |
|       dop_method:DAS DOP                                                                            |
|       avaiable_index_name:[idx1, idx2, idx3, customer]                                              |
|       pruned_index_name:[idx1, idx2, customer]                                                      |
|       stats version:1694254801441111                                                                |
|       dynamic sampling level:0                                                                      |
|   Plan Type:                                                                                        |
|       LOCAL                                                                                         |
|   Note:                                                                                             |
|       Degree of Parallelism is 1 because of hint                                                    |
+-----------------------------------------------------------------------------------------------------+
76 rows in set (0.004 sec)

猜测性分析:
1、当use_batch=false时,左表每次取一条记录,右表对该记录进行匹配并查找符合条件记录,可以通过索引进行过滤,效率较高。
2、当use_batch=true时,左表每次取一批记录,右表对这批记录进行匹配并查找符合条件记录,如果关联条件是等值条件,那么可以将条件进行下压,如果不存在等值条件,那么这对左表每一行只能将右表(索引)所有记录都拿到计算层,在计算层内部进行循环匹配(应该是hash表)。

2 个赞

这里的SSSTORE_READ_ROW_COUNT是0的原因是我按照SQL搜索的,这只是协调线程,我按照traceid搜索就找到了,是符合预期的。

顺便发一下下面 SQL 结果:

WITH table_locs AS (
SELECT
	t.tenant_id,
	t.database_name,
	t.table_id,
	t.table_name,
	t.table_type tablet_type,
	t.tablet_id,
	REPLACE(concat(t.table_name,':',t.partition_name,':',t.subpartition_name),':NULL','') tablet_name,
	t.tablegroup_name,
	t.ls_id,
	t.ZONE, 
	t.ROLE,
	t.svr_ip
FROM
	oceanbase.CDB_OB_TABLE_LOCATIONS t
WHERE
	t.data_table_id IS NULL 
UNION
SELECT
	i.tenant_id,
	i.database_name,
	i.table_id,
	t.table_name,
	i.table_type tablet_type,
	i.tablet_id,
	REPLACE(
		REPLACE(concat(i.table_name,':',i.partition_name,':',i.subpartition_name) ,concat('__idx_', i.data_table_id, '_'),'')
		,':NULL',''
	) tablet_name,
	i.tablegroup_name,
	i.ls_id,
	i.ZONE, 
	i.ROLE,
	i.svr_ip
FROM
	oceanbase.CDB_OB_TABLE_LOCATIONS i
INNER JOIN oceanbase.__all_virtual_table t ON
	( i.tenant_id = t.tenant_id
		AND i.data_table_id = t.table_id  )
WHERE i.data_table_id IS NOT NULL 
)
SELECT
	t.database_name,
	t.ls_id,
	t.ROLE,
	t.svr_ip,
	t.table_name,
	t.tablet_name,
	-- group_concat(s.table_type,',') tablet_types,
	round(sum(s.size)/1024/1024/1024,2) size_gb
FROM
	table_locs t JOIN oceanbase.GV$OB_SSTABLES s 
		ON (t.tenant_id=s.tenant_id AND t.ls_id=s.ls_id AND t.svr_ip=s.svr_ip AND t.tablet_id=s.tablet_id)
WHERE
	t.tenant_id = 1004
	AND t.database_name IN ('tpch10')
	AND t.table_name IN ('customer','nation')
	AND s.table_type NOT IN ('MEMTABLE')
	-- AND t.ROLE IN ('LEADER')
GROUP BY
	t.database_name,
	t.ls_id,
	t.ROLE,
	t.svr_ip,
	t.table_name,
	t.tablet_name 
WITH ROLLUP
ORDER BY 
	t.database_name,
	t.ls_id,
	t.ROLE,
	t.svr_ip,
	t.table_name,
	t.tablet_name
;

当我指定连接顺序时候,将a表作为左表,那就是大表驱动小表,那么在use_batch=true的情况下性能会更好。

obclient [tpch10]> explain select /*+ sql_001 use_nl(a,b) leading(a,b) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+--------------------------------------------------------------------------------------+
| Query Plan                                                                           |
+--------------------------------------------------------------------------------------+
| ===================================================================                  |
| |ID|OPERATOR                        |NAME   |EST.ROWS|EST.TIME(us)|                  |
| -------------------------------------------------------------------                  |
| |0 |SCALAR GROUP BY                 |       |1       |32194067    |                  |
| |1 |└─NESTED-LOOP JOIN              |       |12500000|31967516    |                  |
| |2 |  ├─TABLE FULL SCAN             |a(idx3)|1500000 |52775       |                  |
| |3 |  └─DISTRIBUTED TABLE RANGE SCAN|b      |9       |21          |                  |
| ===================================================================                  |
| Outputs & filters:                                                                   |
| -------------------------------------                                                |
|   0 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256                              |
|       group(nil), agg_func([T_FUN_COUNT(*)])                                         |
|   1 - output(nil), filter(nil), rowset=256                                           |
|       conds(nil), nl_params_([a.C_NATIONKEY(:0)]), use_batch=false                   |
|   2 - output([a.C_NATIONKEY]), filter(nil), rowset=256                               |
|       access([a.C_NATIONKEY]), partitions(p0)                                        |
|       is_index_back=false, is_global_index=false,                                    |
|       range_key([a.C_NATIONKEY], [a.C_CUSTKEY]), range(MIN,MIN ; MAX,MAX)always true |
|   3 - output(nil), filter(nil), rowset=256                                           |
|       access(nil), partitions(p0)                                                    |
|       is_index_back=false, is_global_index=false,                                    |
|       range_key([b.N_NATIONKEY]), range(MIN ; MAX),                                  |
|       range_cond([:0 < b.N_NATIONKEY])                                               |
+--------------------------------------------------------------------------------------+
23 rows in set (0.003 sec)

obclient [tpch10]> select /*+ sql_001 use_nl(a,b) leading(a,b) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (9.341 sec)

obclient [tpch10]> SET _NLJ_BATCHING_ENABLED=true;
Query OK, 0 rows affected (0.001 sec)

obclient [tpch10]> explain select /*+ sql_001 use_nl(a,b) leading(a,b) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+--------------------------------------------------------------------------------------+
| Query Plan                                                                           |
+--------------------------------------------------------------------------------------+
| ===================================================================                  |
| |ID|OPERATOR                        |NAME   |EST.ROWS|EST.TIME(us)|                  |
| -------------------------------------------------------------------                  |
| |0 |SCALAR GROUP BY                 |       |1       |28294067    |                  |
| |1 |└─NESTED-LOOP JOIN              |       |12500000|28067516    |                  |
| |2 |  ├─TABLE FULL SCAN             |a(idx3)|1500000 |52775       |                  |
| |3 |  └─DISTRIBUTED TABLE RANGE SCAN|b      |9       |18          |                  |
| ===================================================================                  |
| Outputs & filters:                                                                   |
| -------------------------------------                                                |
|   0 - output([T_FUN_COUNT(*)]), filter(nil), rowset=256                              |
|       group(nil), agg_func([T_FUN_COUNT(*)])                                         |
|   1 - output(nil), filter(nil), rowset=256                                           |
|       conds(nil), nl_params_([a.C_NATIONKEY(:0)]), use_batch=true                    |
|   2 - output([a.C_NATIONKEY]), filter(nil), rowset=256                               |
|       access([a.C_NATIONKEY]), partitions(p0)                                        |
|       is_index_back=false, is_global_index=false,                                    |
|       range_key([a.C_NATIONKEY], [a.C_CUSTKEY]), range(MIN,MIN ; MAX,MAX)always true |
|   3 - output(nil), filter(nil), rowset=256                                           |
|       access([GROUP_ID]), partitions(p0)                                             |
|       is_index_back=false, is_global_index=false,                                    |
|       range_key([b.N_NATIONKEY]), range(MIN ; MAX),                                  |
|       range_cond([:0 < b.N_NATIONKEY])                                               |
+--------------------------------------------------------------------------------------+
23 rows in set (0.003 sec)

obclient [tpch10]> select /*+ sql_001 use_nl(a,b) leading(a,b) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (5.928 sec)

所以use_batch适合在左表记录数较多的情况下,如果左表记录数较少那么因此还要在计算层构建hash_table匹配(猜测),效率反而不如use_batch=false。

在这个case中对于use_batch=true的情况下计算层内部匹配到底发生了多少次的loop循环在sql_audit中没有(SSSTORE_READ_ROW_COUNT只是对存储层发生的扫描次数),是否加上一些计算层的指标会对分析问题更优帮助呢?

use_batch 这个是什么参数,文档没找到

| database_name | ls_id | ROLE   | svr_ip         | table_name | tablet_name | size_gb |
+---------------+-------+--------+----------------+------------+-------------+---------+
| NULL          |  NULL | NULL   | NULL           | NULL       | NULL        |    0.11 |
| tpch10        |  NULL | NULL   | NULL           | NULL       | NULL        |    0.11 |
| tpch10        |  1001 | NULL   | NULL           | NULL       | NULL        |    0.11 |
| tpch10        |  1001 | LEADER | NULL           | NULL       | NULL        |    0.11 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | NULL       | NULL        |    0.11 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | customer   | NULL        |    0.11 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | customer   | customer    |    0.10 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | customer   | idx1        |    0.01 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | customer   | idx2        |    0.01 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | customer   | idx3        |    0.00 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | nation     | NULL        |    0.00 |
| tpch10        |  1001 | LEADER | 192.168.31.201 | nation     | nation      |    0.00 |
+---------------+-------+--------+----------------+------------+-------------+---------+
12 rows in set (0.231 sec)

可以开启会话trace 分别跑一下两个 SQL 再发一下相关信息。

set session ob_enable_show_trace=true;
select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
show trace;
select /*+ parallel(2) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
show trace;

我当前版本的obclient看不到trace呢

[admin@host0 ~]$ obclient --version
obclient  Ver  Distrib 10.4.18-MariaDB, for Linux (x86_64) using readline 5.1
[admin@host0 ~]$ which obclient
~/.oceanbase-all-in-one/obclient/u01/obclient/bin/obclient

obclient [tpch10]> set session ob_enable_show_trace=true;
Query OK, 0 rows affected (0.001 sec)

obclient [tpch10]> select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (3.421 sec)

obclient [tpch10]> show trace;
Empty set (0.004 sec)

换 mysql 客户端试试看

mysql> set session ob_enable_show_trace=true;
Query OK, 0 rows affected (0.00 sec)

mysql> select /*+ parallel(1) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (3.44 sec)

mysql> show trace;
+-------------------------------------------+----------------------------+-------------+
| Operation                                 | StartTime                  | ElapseTime  |
+-------------------------------------------+----------------------------+-------------+
| com_query_process                         | 2023-09-20 20:34:54.905282 | 3445.521 ms |
| └── mpquery_single_stmt                   | 2023-09-20 20:34:54.905287 | 3445.498 ms |
|     ├── sql_compile                       | 2023-09-20 20:34:54.905296 | 2.376 ms    |
|     │   ├── pc_get_plan                   | 2023-09-20 20:34:54.905298 | 0.011 ms    |
|     │   └── hard_parse                    | 2023-09-20 20:34:54.905338 | 2.320 ms    |
|     │       ├── parse                     | 2023-09-20 20:34:54.905339 | 0.056 ms    |
|     │       ├── resolve                   | 2023-09-20 20:34:54.905408 | 0.245 ms    |
|     │       ├── rewrite                   | 2023-09-20 20:34:54.905719 | 0.458 ms    |
|     │       ├── optimize                  | 2023-09-20 20:34:54.906226 | 1.029 ms    |
|     │       ├── code_generate             | 2023-09-20 20:34:54.907282 | 0.157 ms    |
|     │       └── pc_add_plan               | 2023-09-20 20:34:54.907572 | 0.078 ms    |
|     └── sql_execute                       | 2023-09-20 20:34:54.907707 | 3442.963 ms |
|         ├── open                          | 2023-09-20 20:34:54.907708 | 0.031 ms    |
|         ├── response_result               | 2023-09-20 20:34:54.907756 | 3442.771 ms |
|         │   ├── do_local_das_task         | 2023-09-20 20:34:54.907764 | 0.037 ms    |
|         │   └── do_local_das_task         | 2023-09-20 20:34:54.907891 | 0.034 ms    |
|         └── close                         | 2023-09-20 20:34:58.350558 | 0.104 ms    |
|             ├── close_das_task            | 2023-09-20 20:34:58.350560 | 0.023 ms    |
|             ├── close_das_task            | 2023-09-20 20:34:58.350592 | 0.014 ms    |
|             └── end_transaction           | 2023-09-20 20:34:58.350640 | 0.003 ms    |
+-------------------------------------------+----------------------------+-------------+
20 rows in set (0.01 sec)

mysql> select /*+ parallel(2) */ count(*) from customer a join nation b on a.c_nationkey < b.n_nationkey;
+----------+
| count(*) |
+----------+
| 18002417 |
+----------+
1 row in set (0.06 sec)

mysql> show trace;
+-------------------------------------------------------+----------------------------+------------+
| Operation                                             | StartTime                  | ElapseTime |
+-------------------------------------------------------+----------------------------+------------+
| com_query_process                                     | 2023-09-20 20:35:07.856241 | 61.206 ms  |
| └── mpquery_single_stmt                               | 2023-09-20 20:35:07.856248 | 61.187 ms  |
|     ├── sql_compile                                   | 2023-09-20 20:35:07.856262 | 2.631 ms   |
|     │   ├── pc_get_plan                               | 2023-09-20 20:35:07.856264 | 0.010 ms   |
|     │   └── hard_parse                                | 2023-09-20 20:35:07.856327 | 2.560 ms   |
|     │       ├── parse                                 | 2023-09-20 20:35:07.856329 | 0.062 ms   |
|     │       ├── resolve                               | 2023-09-20 20:35:07.856418 | 0.221 ms   |
|     │       ├── rewrite                               | 2023-09-20 20:35:07.856689 | 0.458 ms   |
|     │       ├── optimize                              | 2023-09-20 20:35:07.857172 | 1.112 ms   |
|     │       ├── code_generate                         | 2023-09-20 20:35:07.858333 | 0.237 ms   |
|     │       └── pc_add_plan                           | 2023-09-20 20:35:07.858722 | 0.156 ms   |
|     └── sql_execute                                   | 2023-09-20 20:35:07.858930 | 58.413 ms  |
|         ├── open                                      | 2023-09-20 20:35:07.858931 | 0.583 ms   |
|         ├── response_result                           | 2023-09-20 20:35:07.859537 | 57.709 ms  |
|         │   ├── px_schedule                           | 2023-09-20 20:35:07.859540 | 5.290 ms   |
|         │   │   ├── px_task                           | 2023-09-20 20:35:07.862766 | 54.251 ms  |
|         │   │   │   ├── do_local_das_task             | 2023-09-20 20:35:07.876883 | 0.052 ms   |
|         │   │   │   └── close_das_task                | 2023-09-20 20:35:07.916938 | 0.007 ms   |
|         │   │   ├── px_task                           | 2023-09-20 20:35:07.866484 | 8.945 ms   |
|         │   │   │   ├── do_local_das_task             | 2023-09-20 20:35:07.866775 | 0.106 ms   |
|         │   │   │   └── close_das_task                | 2023-09-20 20:35:07.875358 | 0.008 ms   |
|         │   │   └── px_task                           | 2023-09-20 20:35:07.873375 | 35.654 ms  |
|         │   │       ├── do_local_das_task             | 2023-09-20 20:35:07.876883 | 0.053 ms   |
|         │   │       └── close_das_task                | 2023-09-20 20:35:07.908955 | 0.007 ms   |
|         │   ├── px_schedule                           | 2023-09-20 20:35:07.875609 | 0.001 ms   |
|         │   └── px_schedule                           | 2023-09-20 20:35:07.917219 | 0.001 ms   |
|         └── close                                     | 2023-09-20 20:35:07.917258 | 0.079 ms   |
|             └── end_transaction                       | 2023-09-20 20:35:07.917322 | 0.002 ms   |
+-------------------------------------------------------+----------------------------+------------+
28 rows in set (0.01 sec)

简单点,就是特点场景下,特定sql执行开启并行,可以得到百倍性能提升。

就像物力资源使用率和响应时间一定是在特定业务场景下才有意义一样

补充下,经过测试。
用到use_batch=true的情况是:走IndexLookupJoin(右表走索引)且不开启并行(parallel=1)。
use_batch=true应该是Block Nested Loop Join。

2 个赞

所以和并行无关,是use_batch=true导致右表全表扫了是不