当MogDB遇到标量子查询中有limit或rownum怎么办

在过去的一些项目中,我们发现对于标量子查询带limit或者rownum的情况下,Oracle的性能非常高效,而MogDB的性能似乎差强人意,那么如果在使用MogDB的过程中遇到了这样的场景,该如何进行优化呢?

这里我们来给大家分享一些优化方法。

首先来看看Oracle的情况

这里我们先模拟构造一些数据,用来测试验证.


create table test02 as select * from dba_objects;
create table test01 as select * from test02;
insert into test01 select * from test01;
insert into test01 select * from test01;
insert into test01 select * from test01;
commit;
insert into test01 select * from test01;
insert into test01 select * from test01;
insert into test01 select * from test01;
commit;
insert into test01 select * from test01;
insert into test01 select * from test01;
insert into test01 select * from test01;
commit;
create index idx_test01_owner on test01(owner);


数据构造完毕之后,我们来看看Oracle 11g中该测试SQL的执行计划如何。

SQL> select count(1) from test01;

  COUNT(1)
----------
  22858240

Elapsed: 00:00:03.75
SQL> select count(1) from test02;

  COUNT(1)
----------
     89290

Elapsed: 00:00:00.07
SQL> 
SQL> SELECT object_id, t1.owner,
  2    (SELECT t2.object_name
  3     FROM test01 t2
  4     WHERE t1.owner = t2.owner
  5       AND rownum <= 1)
  6  FROM test02 t1
  7  WHERE rownum <= 10;

 OBJECT_ID OWNER                          (SELECTT2.OBJECT_NAMEFROMTEST01T2WHERET1.OWNER=T2.OWNERANDRO
---------- ------------------------------ ------------------------------------------------------------
        20 SYS                            ICOL$
        46 SYS                            ICOL$
        28 SYS                            ICOL$
        15 SYS                            ICOL$
        29 SYS                            ICOL$
         3 SYS                            ICOL$
        25 SYS                            ICOL$
        41 SYS                            ICOL$
        54 SYS                            ICOL$
        40 SYS                            ICOL$

10 rows selected.

Elapsed: 00:00:00.01

Execution Plan
----------------------------------------------------------
Plan hash value: 1781923309

-------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name             | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |                  |    10 |   300 |     2   (0)| 00:00:01 |
|*  1 |  COUNT STOPKEY               |                  |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| TEST01           |   250K|    19M|     4   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | IDX_TEST01_OWNER |   100K|       |     3   (0)| 00:00:01 |
|*  4 |  COUNT STOPKEY               |                  |       |       |            |          |
|   5 |   TABLE ACCESS FULL          | TEST02           | 81940 |  2400K|     2   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter(ROWNUM<=1)
   3 - access("T2"."OWNER"=:B1)
   4 - filter(ROWNUM<=10)

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          9  consistent gets
         12  physical reads
          0  redo size
        862  bytes sent via SQL*Net to client
        523  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
         10  rows processed

SQL> 

可以看到,在Oracle 中该SQL执行效率非常高效,毫秒级返回结果。然后在早期的MogDB版本中,处理该SQL性能并不高高效,会走bitmap index scan。

首先我们通过mtk迁移工具将该2个表测试数据迁移到mogdb中,然后测试验证一把。

至于迁移步骤,这里我就不在提了,大家可以参考之前的文章。

MogDB 验证

这里我使用了MogDB 5.0.5版本。废话不多说,直接上测试过程。

[omm@mogdb1 ~]$ gsql -r -d test -Uroger
Password for user roger: 
gsql ((MogDB 5.0.5 build b77f1a82) compiled at 2023-12-08 03:11:47 commit 0 last mr 1804 )
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.

test=> \timing on
Timing is on.
test=> 
test=>    SELECT object_id, t1.owner,
test->   (SELECT t2.object_name
test(>    FROM test01 t2
test(>    WHERE t1.owner = t2.owner
test(>      AND rownum <= 1)
test-> FROM test02 t1
test-> WHERE rownum <= 10;
 object_id | owner | object_name 
-----------+-------+-------------
        20 | SYS   | ICOL$
        46 | SYS   | ICOL$
        28 | SYS   | ICOL$
        15 | SYS   | ICOL$
        29 | SYS   | ICOL$
         3 | SYS   | ICOL$
        25 | SYS   | ICOL$
        41 | SYS   | ICOL$
        54 | SYS   | ICOL$
        40 | SYS   | ICOL$
(10 rows)

Time: 18472.299 ms
test=> 
test=>  explain 
test-> SELECT object_id, t1.owner,
test->   (SELECT t2.object_name
test(>    FROM test01 t2
test(>    WHERE t1.owner = t2.owner
test(>      AND rownum <= 1)
test-> FROM test02 t1
test-> WHERE rownum <= 10;
                                                 QUERY PLAN                                                 
------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.00..179830.95 rows=10 width=11)
   ->  Seq Scan on test02 t1  (cost=0.00..1605908407.74 rows=89301 width=11)
         SubPlan 1
           ->  Limit  (cost=17982.47..17983.07 rows=1 width=24)
                 ->  Bitmap Heap Scan on test01 t2  (cost=17982.47..591299.40 rows=952544 width=24)
                       Recheck Cond: ((t1.owner)::text = (owner)::text)
                       ->  Bitmap Index Scan on idx_test01_owner  (cost=0.00..17744.33 rows=952544 width=0)
                             Index Cond: ((t1.owner)::text = (owner)::text)
(8 rows)

Time: 1.544 ms
test=> 
test=> select t2.object_name from test01 t2 where 'SYS' = t2.owner and rownum <= 1;
 object_name 
-------------
 ICOL$
(1 row)

Time: 1.496 ms
test=> explain select t2.object_name from test01 t2 where 'SYS' = t2.owner and rownum <= 1;
                                QUERY PLAN                                 
---------------------------------------------------------------------------
 Limit  (cost=0.00..0.07 rows=1 width=24)
   ->  Seq Scan on test01 t2  (cost=0.00..687643.20 rows=9726617 width=24)
         Filter: ('SYS'::text = (owner)::text)
(3 rows)

Time: 1.292 ms
test=> 


从第一次执行的情况来看,该SQL需要10多秒,简直是比Oracle慢太多了,无法仍受。实际上我们分析上述的执行计划可以看到,主要慢在了bitmap scan上了。

这里我们暂时用hint禁用该功能。

test=> SELECT /*+ set(enable_bitmapscan off) */ object_id, t1.owner,
test->   (SELECT t2.object_name
test(>    FROM test01 t2
test(>    WHERE t1.owner = t2.owner
test(>      AND rownum <= 1)
test-> FROM test02 t1
test-> WHERE rownum <= 10;
 object_id | owner | object_name 
-----------+-------+-------------
        20 | SYS   | ICOL$
        46 | SYS   | ICOL$
        28 | SYS   | ICOL$
        15 | SYS   | ICOL$
        29 | SYS   | ICOL$
         3 | SYS   | ICOL$
        25 | SYS   | ICOL$
        41 | SYS   | ICOL$
        54 | SYS   | ICOL$
        40 | SYS   | ICOL$
(10 rows)

Time: 3.367 ms
test=> explain SELECT /*+ set(enable_bitmapscan off) */ object_id, t1.owner,
test->   (SELECT t2.object_name
test(>    FROM test01 t2
test(>    WHERE t1.owner = t2.owner
test(>      AND rownum <= 1)
test-> FROM test02 t1
test-> WHERE rownum <= 10;
                                       QUERY PLAN                                       
----------------------------------------------------------------------------------------
 Limit  (cost=0.00..7.49 rows=10 width=11)
   ->  Seq Scan on test02 t1  (cost=0.00..66929.56 rows=89301 width=11)
         SubPlan 1
           ->  Limit  (cost=0.00..0.72 rows=1 width=24)
                 ->  Seq Scan on test01 t2  (cost=0.00..687643.20 rows=952544 width=24)
                       Filter: ((t1.owner)::text = (owner)::text)
(6 rows)

Time: 1.467 ms
test=> 

我们可以看到此时执行计划正常了,快如闪电了。

在6月30号即将发布的新版本中SQL引擎就具备该能力,不再需要人工干预了。

本文由 mdnice 多平台发布

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值