ITPub博客

首页 > 数据库 > Oracle > [20230319]12c paging fetch cost bug.txt

[20230319]12c paging fetch cost bug.txt

原创 Oracle 作者:lfree 时间:2023-03-19 21:00:11 0 删除 编辑

[20230319]12c paging fetch cost bug.txt

--//无意中发现12c paging fetch cost问题,做一个记录:

1.环境:
SCOTT@test01p> @ver1
PORT_STRING                    VERSION        BANNER                                                                               CON_ID
------------------------------ -------------- -------------------------------------------------------------------------------- ----------
IBMPC/WIN_NT64-9.1.0           12.2.0.1.0     Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production              0

SCOTT@test01p> create table t1 as select * from all_objects ;
Table created.

SCOTT@test01p> create index i_t1_object_name on t1(object_name);
Index created.
--//分析表略.
--//注:t1.object_name is not null.

2.测试:
SCOTT@test01p> @sl all
alter session set statistics_level = all;
Session altered.

SCOTT@test01p> select owner, object_type, object_name from t1 order by object_name  fetch first 1 rows only;
OWNER                OBJECT_TYPE          OBJECT_NAME
-------------------- -------------------- -----------
XDB                  OPERATOR             ABSPATH

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  fjwda1wwx6awa, child number 0
-------------------------------------
select owner, object_type, object_name from t1 order by object_name
fetch first 1 rows only
Plan hash value: 2433988517
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |      |      1 |        |       |       |   266 (100)|          |      1 |00:00:00.02 |     347 |       |       |          |
|*  1 |  VIEW                    |      |      1 |      1 |   224 |       |   266   (2)| 00:00:01 |      1 |00:00:00.02 |     347 |       |       |          |
|*  2 |   WINDOW SORT PUSHED RANK|      |      1 |  18643 |   600K|   816K|   266   (2)| 00:00:01 |      1 |00:00:00.02 |     347 |  2048 |  2048 | 2048  (0)|
|   3 |    TABLE ACCESS FULL     | T1   |      1 |  18643 |   600K|       |    96   (2)| 00:00:01 |  18643 |00:00:00.01 |     347 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / from$_subquery$_002@SEL$2
   2 - SEL$1
   3 - SEL$1 / T1@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=1)
   2 - filter(ROW_NUMBER() OVER ( ORDER BY "OBJECT_NAME")<=1)
--//按照道理oracle应该走索引,取1条记录就stop.而实际的情况是走全表扫描.
--//我取1条记录执行计划就这样,其它情况更不用讲了.
--//注我开始以为object_name有null值,实际上这样的情况不存在.表t1定义object_name 就是not null.

--//改写如下呢?
SCOTT@test01p> select owner, object_type, object_name from t1 order by object_name  offset 0 rows fetch  next 1 rows only;
OWNER                OBJECT_TYPE          OBJECT_NAME
-------------------- -------------------- -----------
XDB                  OPERATOR             ABSPATH


SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  ft6pjrrkzkduz, child number 0
-------------------------------------
select owner, object_type, object_name from t1 order by object_name
offset 0 rows fetch  next 1 rows only
Plan hash value: 2433988517
--------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                | Name | Starts | E-Rows |E-Bytes|E-Temp | Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT         |      |      1 |        |       |       |   266 (100)|          |      1 |00:00:00.02 |     347 |       |       |          |
|*  1 |  VIEW                    |      |      1 |  18643 |  4078K|       |   266   (2)| 00:00:01 |      1 |00:00:00.02 |     347 |       |       |          |
|*  2 |   WINDOW SORT PUSHED RANK|      |      1 |  18643 |   600K|   816K|   266   (2)| 00:00:01 |      1 |00:00:00.02 |     347 |  2048 |  2048 | 2048  (0)|
|   3 |    TABLE ACCESS FULL     | T1   |      1 |  18643 |   600K|       |    96   (2)| 00:00:01 |  18643 |00:00:00.01 |     347 |       |       |          |
--------------------------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / from$_subquery$_002@SEL$2
   2 - SEL$1
   3 - SEL$1 / T1@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(("from$_subquery$_002"."rowlimit_$$_rownumber"<=CASE  WHEN (0>=0) THEN 0 ELSE 0 END +1 AND
              "from$_subquery$_002"."rowlimit_$$_rownumber">0))
   2 - filter(ROW_NUMBER() OVER ( ORDER BY "OBJECT_NAME")<=CASE  WHEN (0>=0) THEN 0 ELSE 0 END +1)
30 rows selected.
--//还是选择全表扫描.注意这样写过滤条件不同.

3.继续测试:
--//直接加入提示index(t1 i_t1_object_name)呢?
SCOTT@test01p> select /*+ index(t1 i_t1_object_name) */ owner, object_type, object_name from t1 order by object_name  fetch first 1 rows only;
OWNER                OBJECT_TYPE          OBJECT_NAME
-------------------- -------------------- --------------------
XDB                  OPERATOR             ABSPATH

SCOTT@test01p> @ dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  ba8cdjvatwk95, child number 0
-------------------------------------
select /*+ index(t1 i_t1_object_name) */ owner, object_type,
object_name from t1 order by object_name  fetch first 1 rows only
Plan hash value: 1887114361
--------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name             | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time   | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |                  |      1 |        |       |  8319 (100)|          |      1 |00:00:00.01 |       5 |
|*  1 |  VIEW                         |                  |      1 |      1 |   224 |  8319   (1)| 00:00:01 |      1 |00:00:00.01 |       5 |
|*  2 |   WINDOW NOSORT STOPKEY       |                  |      1 |  18643 |   600K|  8319   (1)| 00:00:01 |      1 |00:00:00.01 |       5 |
|   3 |    TABLE ACCESS BY INDEX ROWID| T1               |      1 |  18643 |   600K|  8319   (1)| 00:00:01 |      2 |00:00:00.01 |       5 |
|   4 |     INDEX FULL SCAN           | I_T1_OBJECT_NAME |      1 |  18643 |       |    80   (0)| 00:00:01 |      2 |00:00:00.01 |       3 |
--------------------------------------------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - SEL$1 / from$_subquery$_002@SEL$2
   2 - SEL$1
   3 - SEL$1 / T1@SEL$1
   4 - SEL$1 / T1@SEL$1

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("from$_subquery$_002"."rowlimit_$$_rownumber"<=1)
   2 - filter(ROW_NUMBER() OVER ( ORDER BY "OBJECT_NAME")<=1)
31 rows selected.
--//直接使用INDEX FULL SCAN,取1个值就ok了.buffers=5,明显这个执行计划是最优的.
--//而如果你仔细看cost=8319.取前面的选择全表扫描的执行计划cost=266.oracle在没有提示的情况下选择全表扫描就很正常了.
--//问题在于id=3的cost上等于8319.
--//还有一点奇怪的地方是fetch 1条记录.而实际A-ROWS=2(id=3,4).
--//而且id=4的cost=80,明显是全扫描索引的成本,这一步就已经加大了许多.
--//看来这是12c上的一个bug.paging fetch cost计算有误.

--//我估计19c以上版本不存在这个问题.有机会测试看看!!

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/267265/viewspace-2940439/ ,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
熟悉oracle相关技术,擅长sql优化,rman备份与恢复,熟悉linux shell编程。

注册时间:2008-01-03

  • 博文量
    4014
  • 访问量
    7991212