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

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

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

首先来看看Oracle的情况

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

sql 复制代码
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 复制代码
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版本。废话不多说,直接上测试过程。

ini 复制代码
[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禁用该功能。

sql 复制代码
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多平台发布

相关推荐
一屉大大大花卷24 分钟前
初识Neo4j之入门介绍(一)
数据库·neo4j
周胡杰1 小时前
鸿蒙arkts使用关系型数据库,使用DB Browser for SQLite连接和查看数据库数据?使用TaskPool进行频繁数据库操作
前端·数据库·华为·harmonyos·鸿蒙·鸿蒙系统
wkj0011 小时前
navicate如何设置数据库引擎
数据库·mysql
赵渝强老师1 小时前
【赵渝强老师】Oracle RMAN的目录数据库
数据库·oracle
暖暖木头1 小时前
Oracle注释详解
数据库·oracle
御控工业物联网1 小时前
御控网关如何实现MQTT、MODBUS、OPCUA、SQL、HTTP之间协议转换
数据库·sql·http
GJCTYU3 小时前
spring中@Transactional注解和事务的实战理解附代码
数据库·spring boot·后端·spring·oracle·mybatis
MicroTech20253 小时前
微算法科技(NASDAQ: MLGO)探索Grover量子搜索算法,利用量子叠加和干涉原理,实现在无序数据库中快速定位目标信息的效果。
数据库·科技·算法
Code季风3 小时前
SQL关键字快速入门:CASE 实现条件逻辑
javascript·数据库·sql
weixin_478689763 小时前
操作系统【2】【内存管理】【虚拟内存】【参考小林code】
数据库·nosql